mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
Fix godeps
This commit is contained in:
parent
de59ede6b2
commit
d16b39abc5
30
Godeps/Godeps.json
generated
30
Godeps/Godeps.json
generated
@ -676,11 +676,6 @@
|
||||
"ImportPath": "github.com/coreos/go-semver/semver",
|
||||
"Rev": "568e959cd89871e61434c1143528d9162da89ef2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-systemd/activation",
|
||||
"Comment": "v8-2-g4484981",
|
||||
"Rev": "4484981625c1a6a2ecb40a390fcb6a9bcfee76e3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-systemd/daemon",
|
||||
"Comment": "v8-2-g4484981",
|
||||
@ -2141,31 +2136,6 @@
|
||||
"ImportPath": "github.com/shurcooL/sanitized_anchor_name",
|
||||
"Rev": "10ef21a441db47d8b13ebcc5fd2310f636973c77"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/skynetservices/skydns/cache",
|
||||
"Comment": "2.5.3a-41-g00ade30",
|
||||
"Rev": "00ade3024f047d26130abf161900e0adb72a06f1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/skynetservices/skydns/metrics",
|
||||
"Comment": "2.5.3a-41-g00ade30",
|
||||
"Rev": "00ade3024f047d26130abf161900e0adb72a06f1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/skynetservices/skydns/msg",
|
||||
"Comment": "2.5.3a-41-g00ade30",
|
||||
"Rev": "00ade3024f047d26130abf161900e0adb72a06f1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/skynetservices/skydns/server",
|
||||
"Comment": "2.5.3a-41-g00ade30",
|
||||
"Rev": "00ade3024f047d26130abf161900e0adb72a06f1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/skynetservices/skydns/singleflight",
|
||||
"Comment": "2.5.3a-41-g00ade30",
|
||||
"Rev": "00ade3024f047d26130abf161900e0adb72a06f1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/afero",
|
||||
"Rev": "b28a7effac979219c2a2ed6205a4d70e4b1bcd02"
|
||||
|
344
Godeps/LICENSES
generated
344
Godeps/LICENSES
generated
@ -23236,205 +23236,6 @@ Apache License
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/coreos/go-systemd/activation licensed under: =
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
= vendor/github.com/coreos/go-systemd/LICENSE 19cbd64715b51267a47bf3750cc6a8a5 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/coreos/go-systemd/daemon licensed under: =
|
||||
|
||||
@ -67078,151 +66879,6 @@ THE SOFTWARE.
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/skynetservices/skydns/cache licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 The SkyDNS Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
= vendor/github.com/skynetservices/skydns/LICENSE 132bec980d83cb58e26698e7f4832569 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/skynetservices/skydns/metrics licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 The SkyDNS Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
= vendor/github.com/skynetservices/skydns/LICENSE 132bec980d83cb58e26698e7f4832569 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/skynetservices/skydns/msg licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 The SkyDNS Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
= vendor/github.com/skynetservices/skydns/LICENSE 132bec980d83cb58e26698e7f4832569 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/skynetservices/skydns/server licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 The SkyDNS Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
= vendor/github.com/skynetservices/skydns/LICENSE 132bec980d83cb58e26698e7f4832569 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/skynetservices/skydns/singleflight licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 The SkyDNS Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
= vendor/github.com/skynetservices/skydns/LICENSE 132bec980d83cb58e26698e7f4832569 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/spf13/afero licensed under: =
|
||||
|
||||
|
70
vendor/BUILD
vendored
70
vendor/BUILD
vendored
@ -1946,16 +1946,6 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/coreos/go-systemd/activation",
|
||||
srcs = [
|
||||
"github.com/coreos/go-systemd/activation/files.go",
|
||||
"github.com/coreos/go-systemd/activation/listeners.go",
|
||||
"github.com/coreos/go-systemd/activation/packetconns.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/coreos/go-systemd/daemon",
|
||||
srcs = ["github.com/coreos/go-systemd/daemon/sdnotify.go"],
|
||||
@ -6036,66 +6026,6 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/skynetservices/skydns/cache",
|
||||
srcs = [
|
||||
"github.com/skynetservices/skydns/cache/cache.go",
|
||||
"github.com/skynetservices/skydns/cache/hit.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/miekg/dns"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/skynetservices/skydns/metrics",
|
||||
srcs = ["github.com/skynetservices/skydns/metrics/metrics.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/miekg/dns",
|
||||
"//vendor:github.com/prometheus/client_golang/prometheus",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/skynetservices/skydns/msg",
|
||||
srcs = ["github.com/skynetservices/skydns/msg/service.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/miekg/dns"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/skynetservices/skydns/server",
|
||||
srcs = [
|
||||
"github.com/skynetservices/skydns/server/backend.go",
|
||||
"github.com/skynetservices/skydns/server/config.go",
|
||||
"github.com/skynetservices/skydns/server/dnssec.go",
|
||||
"github.com/skynetservices/skydns/server/doc.go",
|
||||
"github.com/skynetservices/skydns/server/exchange.go",
|
||||
"github.com/skynetservices/skydns/server/forwarding.go",
|
||||
"github.com/skynetservices/skydns/server/log.go",
|
||||
"github.com/skynetservices/skydns/server/msg.go",
|
||||
"github.com/skynetservices/skydns/server/nsec3.go",
|
||||
"github.com/skynetservices/skydns/server/server.go",
|
||||
"github.com/skynetservices/skydns/server/stub.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/coreos/etcd/client",
|
||||
"//vendor:github.com/coreos/go-systemd/activation",
|
||||
"//vendor:github.com/miekg/dns",
|
||||
"//vendor:github.com/skynetservices/skydns/cache",
|
||||
"//vendor:github.com/skynetservices/skydns/metrics",
|
||||
"//vendor:github.com/skynetservices/skydns/msg",
|
||||
"//vendor:github.com/skynetservices/skydns/singleflight",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/skynetservices/skydns/singleflight",
|
||||
srcs = ["github.com/skynetservices/skydns/singleflight/singleflight.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/spf13/afero",
|
||||
srcs = [
|
||||
|
52
vendor/github.com/coreos/go-systemd/activation/files.go
generated
vendored
52
vendor/github.com/coreos/go-systemd/activation/files.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package activation implements primitives for systemd socket activation.
|
||||
package activation
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// based on: https://gist.github.com/alberts/4640792
|
||||
const (
|
||||
listenFdsStart = 3
|
||||
)
|
||||
|
||||
func Files(unsetEnv bool) []*os.File {
|
||||
if unsetEnv {
|
||||
defer os.Unsetenv("LISTEN_PID")
|
||||
defer os.Unsetenv("LISTEN_FDS")
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
|
||||
if err != nil || pid != os.Getpid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
|
||||
if err != nil || nfds == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
files := make([]*os.File, 0, nfds)
|
||||
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
|
||||
syscall.CloseOnExec(fd)
|
||||
files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
62
vendor/github.com/coreos/go-systemd/activation/listeners.go
generated
vendored
62
vendor/github.com/coreos/go-systemd/activation/listeners.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Listeners returns a slice containing a net.Listener for each matching socket type
|
||||
// passed to this process.
|
||||
//
|
||||
// The order of the file descriptors is preserved in the returned slice.
|
||||
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
||||
// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener}
|
||||
func Listeners(unsetEnv bool) ([]net.Listener, error) {
|
||||
files := Files(unsetEnv)
|
||||
listeners := make([]net.Listener, len(files))
|
||||
|
||||
for i, f := range files {
|
||||
if pc, err := net.FileListener(f); err == nil {
|
||||
listeners[i] = pc
|
||||
}
|
||||
}
|
||||
return listeners, nil
|
||||
}
|
||||
|
||||
// TLSListeners returns a slice containing a net.listener for each matching TCP socket type
|
||||
// passed to this process.
|
||||
// It uses default Listeners func and forces TCP sockets handlers to use TLS based on tlsConfig.
|
||||
func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) {
|
||||
listeners, err := Listeners(unsetEnv)
|
||||
|
||||
if listeners == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tlsConfig != nil && err == nil {
|
||||
tlsConfig.NextProtos = []string{"http/1.1"}
|
||||
|
||||
for i, l := range listeners {
|
||||
// Activate TLS only for TCP sockets
|
||||
if l.Addr().Network() == "tcp" {
|
||||
listeners[i] = tls.NewListener(l, tlsConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listeners, err
|
||||
}
|
37
vendor/github.com/coreos/go-systemd/activation/packetconns.go
generated
vendored
37
vendor/github.com/coreos/go-systemd/activation/packetconns.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// PacketConns returns a slice containing a net.PacketConn for each matching socket type
|
||||
// passed to this process.
|
||||
//
|
||||
// The order of the file descriptors is preserved in the returned slice.
|
||||
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
||||
// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn}
|
||||
func PacketConns(unsetEnv bool) ([]net.PacketConn, error) {
|
||||
files := Files(unsetEnv)
|
||||
conns := make([]net.PacketConn, len(files))
|
||||
|
||||
for i, f := range files {
|
||||
if pc, err := net.FilePacketConn(f); err == nil {
|
||||
conns[i] = pc
|
||||
}
|
||||
}
|
||||
return conns, nil
|
||||
}
|
21
vendor/github.com/skynetservices/skydns/LICENSE
generated
vendored
21
vendor/github.com/skynetservices/skydns/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 The SkyDNS Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
167
vendor/github.com/skynetservices/skydns/cache/cache.go
generated
vendored
167
vendor/github.com/skynetservices/skydns/cache/cache.go
generated
vendored
@ -1,167 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package cache
|
||||
|
||||
// Cache that holds RRs and for DNSSEC an RRSIG.
|
||||
|
||||
// TODO(miek): there is a lot of copying going on to copy myself out of data
|
||||
// races. This should be optimized.
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Elem hold an answer and additional section that returned from the cache.
|
||||
// The signature is put in answer, extra is empty there. This wastes some memory.
|
||||
type elem struct {
|
||||
expiration time.Time // time added + TTL, after this the elem is invalid
|
||||
msg *dns.Msg
|
||||
}
|
||||
|
||||
// Cache is a cache that holds on the a number of RRs or DNS messages. The cache
|
||||
// eviction is randomized.
|
||||
type Cache struct {
|
||||
sync.RWMutex
|
||||
|
||||
capacity int
|
||||
m map[string]*elem
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
// New returns a new cache with the capacity and the ttl specified.
|
||||
func New(capacity, ttl int) *Cache {
|
||||
c := new(Cache)
|
||||
c.m = make(map[string]*elem)
|
||||
c.capacity = capacity
|
||||
c.ttl = time.Duration(ttl) * time.Second
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cache) Capacity() int { return c.capacity }
|
||||
|
||||
func (c *Cache) Remove(s string) {
|
||||
c.Lock()
|
||||
delete(c.m, s)
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// EvictRandom removes a random member a the cache.
|
||||
// Must be called under a write lock.
|
||||
func (c *Cache) EvictRandom() {
|
||||
clen := len(c.m)
|
||||
if clen < c.capacity {
|
||||
return
|
||||
}
|
||||
i := c.capacity - clen
|
||||
for k, _ := range c.m {
|
||||
delete(c.m, k)
|
||||
i--
|
||||
if i == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InsertMessage inserts a message in the Cache. We will cache it for ttl seconds, which
|
||||
// should be a small (60...300) integer.
|
||||
func (c *Cache) InsertMessage(s string, msg *dns.Msg) {
|
||||
if c.capacity <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
if _, ok := c.m[s]; !ok {
|
||||
c.m[s] = &elem{time.Now().UTC().Add(c.ttl), msg.Copy()}
|
||||
|
||||
}
|
||||
c.EvictRandom()
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// InsertSignature inserts a signature, the expiration time is used as the cache ttl.
|
||||
func (c *Cache) InsertSignature(s string, sig *dns.RRSIG) {
|
||||
if c.capacity <= 0 {
|
||||
return
|
||||
}
|
||||
c.Lock()
|
||||
|
||||
if _, ok := c.m[s]; !ok {
|
||||
m := ((int64(sig.Expiration) - time.Now().Unix()) / (1 << 31)) - 1
|
||||
if m < 0 {
|
||||
m = 0
|
||||
}
|
||||
t := time.Unix(int64(sig.Expiration)-(m*(1<<31)), 0).UTC()
|
||||
c.m[s] = &elem{t, &dns.Msg{Answer: []dns.RR{dns.Copy(sig)}}}
|
||||
}
|
||||
c.EvictRandom()
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// Search returns a dns.Msg, the expiration time and a boolean indicating if we found something
|
||||
// in the cache.
|
||||
func (c *Cache) Search(s string) (*dns.Msg, time.Time, bool) {
|
||||
if c.capacity <= 0 {
|
||||
return nil, time.Time{}, false
|
||||
}
|
||||
c.RLock()
|
||||
if e, ok := c.m[s]; ok {
|
||||
e1 := e.msg.Copy()
|
||||
c.RUnlock()
|
||||
return e1, e.expiration, true
|
||||
}
|
||||
c.RUnlock()
|
||||
return nil, time.Time{}, false
|
||||
}
|
||||
|
||||
// Key creates a hash key from a question section. It creates a different key
|
||||
// for requests with DNSSEC.
|
||||
func Key(q dns.Question, dnssec, tcp bool) string {
|
||||
h := sha1.New()
|
||||
i := append([]byte(q.Name), packUint16(q.Qtype)...)
|
||||
if dnssec {
|
||||
i = append(i, byte(255))
|
||||
}
|
||||
if tcp {
|
||||
i = append(i, byte(254))
|
||||
}
|
||||
return string(h.Sum(i))
|
||||
}
|
||||
|
||||
// Key uses the name, type and rdata, which is serialized and then hashed as the key for the lookup.
|
||||
func KeyRRset(rrs []dns.RR) string {
|
||||
h := sha1.New()
|
||||
i := []byte(rrs[0].Header().Name)
|
||||
i = append(i, packUint16(rrs[0].Header().Rrtype)...)
|
||||
for _, r := range rrs {
|
||||
switch t := r.(type) { // we only do a few type, serialize these manually
|
||||
case *dns.SOA:
|
||||
// We only fiddle with the serial so store that.
|
||||
i = append(i, packUint32(t.Serial)...)
|
||||
case *dns.SRV:
|
||||
i = append(i, packUint16(t.Priority)...)
|
||||
i = append(i, packUint16(t.Weight)...)
|
||||
i = append(i, packUint16(t.Weight)...)
|
||||
i = append(i, []byte(t.Target)...)
|
||||
case *dns.A:
|
||||
i = append(i, []byte(t.A)...)
|
||||
case *dns.AAAA:
|
||||
i = append(i, []byte(t.AAAA)...)
|
||||
case *dns.NSEC3:
|
||||
i = append(i, []byte(t.NextDomain)...)
|
||||
// Bitmap does not differentiate in SkyDNS.
|
||||
case *dns.DNSKEY:
|
||||
case *dns.NS:
|
||||
case *dns.TXT:
|
||||
}
|
||||
}
|
||||
return string(h.Sum(i))
|
||||
}
|
||||
|
||||
func packUint16(i uint16) []byte { return []byte{byte(i >> 8), byte(i)} }
|
||||
func packUint32(i uint32) []byte { return []byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)} }
|
31
vendor/github.com/skynetservices/skydns/cache/hit.go
generated
vendored
31
vendor/github.com/skynetservices/skydns/cache/hit.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Hit returns a dns message from the cache. If the message's TTL is expired nil
|
||||
// is returned and the message is removed from the cache.
|
||||
func (c *Cache) Hit(question dns.Question, dnssec, tcp bool, msgid uint16) *dns.Msg {
|
||||
key := Key(question, dnssec, tcp)
|
||||
m1, exp, hit := c.Search(key)
|
||||
if hit {
|
||||
// Cache hit! \o/
|
||||
if time.Since(exp) < 0 {
|
||||
m1.Id = msgid
|
||||
m1.Compress = true
|
||||
// Even if something ended up with the TC bit *in* the cache, set it to off
|
||||
m1.Truncated = false
|
||||
return m1
|
||||
}
|
||||
// Expired! /o\
|
||||
c.Remove(key)
|
||||
}
|
||||
return nil
|
||||
}
|
186
vendor/github.com/skynetservices/skydns/metrics/metrics.go
generated
vendored
186
vendor/github.com/skynetservices/skydns/metrics/metrics.go
generated
vendored
@ -1,186 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
Port = os.Getenv("PROMETHEUS_PORT")
|
||||
Path = envOrDefault("PROMETHEUS_PATH", "/metrics")
|
||||
Namespace = envOrDefault("PROMETHEUS_NAMESPACE", "skydns")
|
||||
Subsystem = envOrDefault("PROMETHEUS_SUBSYSTEM", "skydns")
|
||||
|
||||
requestCount *prometheus.CounterVec
|
||||
requestDuration *prometheus.HistogramVec
|
||||
responseSize *prometheus.HistogramVec
|
||||
errorCount *prometheus.CounterVec
|
||||
cacheMiss *prometheus.CounterVec
|
||||
)
|
||||
|
||||
type (
|
||||
System string
|
||||
Cause string
|
||||
CacheType string
|
||||
)
|
||||
|
||||
var (
|
||||
Auth System = "auth"
|
||||
Cache System = "cache"
|
||||
Rec System = "recursive"
|
||||
Reverse System = "reverse"
|
||||
Stub System = "stub"
|
||||
|
||||
Nxdomain Cause = "nxdomain"
|
||||
Nodata Cause = "nodata"
|
||||
Truncated Cause = "truncated"
|
||||
Refused Cause = "refused"
|
||||
Overflow Cause = "overflow"
|
||||
Fail Cause = "servfail"
|
||||
|
||||
Response CacheType = "response"
|
||||
Signature CacheType = "signature"
|
||||
)
|
||||
|
||||
func defineMetrics() {
|
||||
requestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: Namespace,
|
||||
Subsystem: Subsystem,
|
||||
Name: "dns_request_count_total",
|
||||
Help: "Counter of DNS requests made.",
|
||||
}, []string{"system"})
|
||||
|
||||
requestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: Namespace,
|
||||
Subsystem: Subsystem,
|
||||
Name: "dns_request_duration_seconds",
|
||||
Help: "Histogram of the time (in seconds) each request took to resolve.",
|
||||
Buckets: append([]float64{0.001, 0.003}, prometheus.DefBuckets...),
|
||||
}, []string{"system"})
|
||||
|
||||
responseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: Namespace,
|
||||
Subsystem: Subsystem,
|
||||
Name: "dns_response_size_bytes",
|
||||
Help: "Size of the returns response in bytes.",
|
||||
Buckets: []float64{0, 512, 1024, 1500, 2048, 4096,
|
||||
8192, 12288, 16384, 20480, 24576, 28672, 32768, 36864,
|
||||
40960, 45056, 49152, 53248, 57344, 61440, 65536,
|
||||
},
|
||||
}, []string{"system"})
|
||||
|
||||
errorCount = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: Namespace,
|
||||
Subsystem: Subsystem,
|
||||
Name: "dns_error_count_total",
|
||||
Help: "Counter of DNS requests resulting in an error.",
|
||||
}, []string{"system", "cause"})
|
||||
|
||||
cacheMiss = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: Namespace,
|
||||
Subsystem: Subsystem,
|
||||
Name: "dns_cachemiss_count_total",
|
||||
Help: "Counter of DNS requests that result in a cache miss.",
|
||||
}, []string{"cache"})
|
||||
}
|
||||
|
||||
// Metrics registers the DNS metrics to Prometheus, and starts the internal metrics
|
||||
// server if the environment variable PROMETHEUS_PORT is set.
|
||||
func Metrics() error {
|
||||
// We do this in a function instead of using var + init(), because we want to
|
||||
// able to set Namespace and/or Subsystem.
|
||||
if Port == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := strconv.Atoi(Port)
|
||||
if err != nil {
|
||||
fmt.Errorf("bad port for prometheus: %s", Port)
|
||||
}
|
||||
|
||||
defineMetrics()
|
||||
|
||||
prometheus.MustRegister(requestCount)
|
||||
prometheus.MustRegister(requestDuration)
|
||||
prometheus.MustRegister(responseSize)
|
||||
prometheus.MustRegister(errorCount)
|
||||
prometheus.MustRegister(cacheMiss)
|
||||
|
||||
http.Handle(Path, prometheus.Handler())
|
||||
go func() {
|
||||
fmt.Errorf("%s", http.ListenAndServe(":"+Port, nil))
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReportDuration(resp *dns.Msg, start time.Time, sys System) {
|
||||
if requestDuration == nil || responseSize == nil {
|
||||
return
|
||||
}
|
||||
|
||||
rlen := float64(0)
|
||||
if resp != nil {
|
||||
rlen = float64(resp.Len())
|
||||
}
|
||||
requestDuration.WithLabelValues(string(sys)).Observe(float64(time.Since(start)) / float64(time.Second))
|
||||
responseSize.WithLabelValues(string(sys)).Observe(rlen)
|
||||
}
|
||||
|
||||
func ReportRequestCount(req *dns.Msg, sys System) {
|
||||
if requestCount == nil {
|
||||
return
|
||||
}
|
||||
|
||||
requestCount.WithLabelValues(string(sys)).Inc()
|
||||
}
|
||||
|
||||
func ReportErrorCount(resp *dns.Msg, sys System) {
|
||||
if resp == nil || errorCount == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Truncated {
|
||||
errorCount.WithLabelValues(string(sys), string(Truncated)).Inc()
|
||||
return
|
||||
}
|
||||
if resp.Len() > dns.MaxMsgSize {
|
||||
errorCount.WithLabelValues(string(sys), string(Overflow)).Inc()
|
||||
return
|
||||
}
|
||||
|
||||
switch resp.Rcode {
|
||||
case dns.RcodeServerFailure:
|
||||
errorCount.WithLabelValues(string(sys), string(Fail)).Inc()
|
||||
case dns.RcodeRefused:
|
||||
errorCount.WithLabelValues(string(sys), string(Refused)).Inc()
|
||||
case dns.RcodeNameError:
|
||||
errorCount.WithLabelValues(string(sys), string(Nxdomain)).Inc()
|
||||
// nodata ??
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ReportCacheMiss(ca CacheType) {
|
||||
if cacheMiss == nil {
|
||||
return
|
||||
}
|
||||
cacheMiss.WithLabelValues(string(ca)).Inc()
|
||||
}
|
||||
|
||||
func envOrDefault(env, def string) string {
|
||||
e := os.Getenv(env)
|
||||
if e != "" {
|
||||
return e
|
||||
}
|
||||
return def
|
||||
}
|
221
vendor/github.com/skynetservices/skydns/msg/service.go
generated
vendored
221
vendor/github.com/skynetservices/skydns/msg/service.go
generated
vendored
@ -1,221 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package msg
|
||||
|
||||
import (
|
||||
"net"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// PathPrefix is the prefix used to store SkyDNS data in the backend.
|
||||
// It defaults to `skydns`.
|
||||
// You can change it by set `path-prefix` configuration or SKYDNS_PATH_PREFIX env. variable.
|
||||
// Then:
|
||||
// The SkyDNS's configuration object should be stored under the key "/mydns/config";
|
||||
// The etcd path of domain `service.staging.skydns.local.` will be "/mydns/local/skydns/staging/service".
|
||||
var PathPrefix string = "skydns"
|
||||
|
||||
// This *is* the rdata from a SRV record, but with a twist.
|
||||
// Host (Target in SRV) must be a domain name, but if it looks like an IP
|
||||
// address (4/6), we will treat it like an IP address.
|
||||
type Service struct {
|
||||
Host string `json:"host,omitempty"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
Weight int `json:"weight,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Mail bool `json:"mail,omitempty"` // Be an MX record. Priority becomes Preference.
|
||||
Ttl uint32 `json:"ttl,omitempty"`
|
||||
|
||||
// When a SRV record with a "Host: IP-address" is added, we synthesize
|
||||
// a srv.Target domain name. Normally we convert the full Key where
|
||||
// the record lives to a DNS name and use this as the srv.Target. When
|
||||
// TargetStrip > 0 we strip the left most TargetStrip labels from the
|
||||
// DNS name.
|
||||
TargetStrip int `json:"targetstrip,omitempty"`
|
||||
|
||||
// Group is used to group (or *not* to group) different services
|
||||
// together. Services with an identical Group are returned in the same
|
||||
// answer.
|
||||
Group string `json:"group,omitempty"`
|
||||
|
||||
// Etcd key where we found this service and ignored from json un-/marshalling
|
||||
Key string `json:"-"`
|
||||
}
|
||||
|
||||
// NewSRV returns a new SRV record based on the Service.
|
||||
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
|
||||
host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
|
||||
|
||||
return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl},
|
||||
Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host}
|
||||
}
|
||||
|
||||
// NewMX returns a new MX record based on the Service.
|
||||
func (s *Service) NewMX(name string) *dns.MX {
|
||||
host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
|
||||
|
||||
return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl},
|
||||
Preference: uint16(s.Priority), Mx: host}
|
||||
}
|
||||
|
||||
// NewA returns a new A record based on the Service.
|
||||
func (s *Service) NewA(name string, ip net.IP) *dns.A {
|
||||
return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip}
|
||||
}
|
||||
|
||||
// NewAAAA returns a new AAAA record based on the Service.
|
||||
func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA {
|
||||
return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip}
|
||||
}
|
||||
|
||||
// NewCNAME returns a new CNAME record based on the Service.
|
||||
func (s *Service) NewCNAME(name string, target string) *dns.CNAME {
|
||||
return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.Ttl}, Target: target}
|
||||
}
|
||||
|
||||
// NewNS returns a new NS record based on the Service.
|
||||
func (s *Service) NewNS(name string, target string) *dns.NS {
|
||||
return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.Ttl}, Ns: target}
|
||||
}
|
||||
|
||||
// NewTXT returns a new TXT record based on the Service.
|
||||
func (s *Service) NewTXT(name string) *dns.TXT {
|
||||
return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.Ttl}, Txt: split255(s.Text)}
|
||||
}
|
||||
|
||||
// NewPTR returns a new PTR record based on the Service.
|
||||
func (s *Service) NewPTR(name string, ttl uint32) *dns.PTR {
|
||||
return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: ttl}, Ptr: dns.Fqdn(s.Host)}
|
||||
}
|
||||
|
||||
// As Path, but if a name contains wildcards (* or any), the name will be
|
||||
// chopped of before the (first) wildcard, and we do a highler evel search and
|
||||
// later find the matching names. So service.*.skydns.local, will look for all
|
||||
// services under skydns.local and will later check for names that match
|
||||
// service.*.skydns.local. If a wildcard is found the returned bool is true.
|
||||
func PathWithWildcard(s string) (string, bool) {
|
||||
l := dns.SplitDomainName(s)
|
||||
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
for i, k := range l {
|
||||
if k == "*" || k == "any" {
|
||||
return path.Join(append([]string{"/" + PathPrefix + "/"}, l[:i]...)...), true
|
||||
}
|
||||
}
|
||||
return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...), false
|
||||
}
|
||||
|
||||
// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
|
||||
// the resulting key will be /skydns/local/skydns/staging/service .
|
||||
func Path(s string) string {
|
||||
l := dns.SplitDomainName(s)
|
||||
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...)
|
||||
}
|
||||
|
||||
// Domain is the opposite of Path.
|
||||
func Domain(s string) string {
|
||||
l := strings.Split(s, "/")
|
||||
// start with 1, to strip /skydns
|
||||
for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
return dns.Fqdn(strings.Join(l[1:len(l)-1], "."))
|
||||
}
|
||||
|
||||
// Group checks the services in sx, it looks for a Group attribute on the shortest
|
||||
// keys. If there are multiple shortest keys *and* the group attribute disagrees (and
|
||||
// is not empty), we don't consider it a group.
|
||||
// If a group is found, only services with *that* group (or no group) will be returned.
|
||||
func Group(sx []Service) []Service {
|
||||
if len(sx) == 0 {
|
||||
return sx
|
||||
}
|
||||
|
||||
// Shortest key with group attribute sets the group for this set.
|
||||
group := sx[0].Group
|
||||
slashes := strings.Count(sx[0].Key, "/")
|
||||
length := make([]int, len(sx))
|
||||
for i, s := range sx {
|
||||
x := strings.Count(s.Key, "/")
|
||||
length[i] = x
|
||||
if x < slashes {
|
||||
if s.Group == "" {
|
||||
break
|
||||
}
|
||||
slashes = x
|
||||
group = s.Group
|
||||
}
|
||||
}
|
||||
|
||||
if group == "" {
|
||||
return sx
|
||||
}
|
||||
|
||||
ret := []Service{} // with slice-tricks in sx we can prolly save this allocation (TODO)
|
||||
|
||||
for i, s := range sx {
|
||||
if s.Group == "" {
|
||||
ret = append(ret, s)
|
||||
continue
|
||||
}
|
||||
|
||||
// Disagreement on the same level
|
||||
if length[i] == slashes && s.Group != group {
|
||||
return sx
|
||||
}
|
||||
|
||||
if s.Group == group {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Split255 splits a string into 255 byte chunks.
|
||||
func split255(s string) []string {
|
||||
if len(s) < 255 {
|
||||
return []string{s}
|
||||
}
|
||||
sx := []string{}
|
||||
p, i := 0, 255
|
||||
for {
|
||||
if i <= len(s) {
|
||||
sx = append(sx, s[p:i])
|
||||
} else {
|
||||
sx = append(sx, s[p:])
|
||||
break
|
||||
|
||||
}
|
||||
p, i = p+255, i+255
|
||||
}
|
||||
|
||||
return sx
|
||||
}
|
||||
|
||||
// targetStrip strips "targetstrip" labels from the left side of the fully qualified name.
|
||||
func targetStrip(name string, targetStrip int) string {
|
||||
if targetStrip == 0 {
|
||||
return name
|
||||
}
|
||||
|
||||
offset, end := 0, false
|
||||
for i := 0; i < targetStrip; i++ {
|
||||
offset, end = dns.NextLabel(name, offset)
|
||||
}
|
||||
if end {
|
||||
// We overshot the name, use the orignal one.
|
||||
offset = 0
|
||||
}
|
||||
name = name[offset:]
|
||||
return name
|
||||
}
|
46
vendor/github.com/skynetservices/skydns/server/backend.go
generated
vendored
46
vendor/github.com/skynetservices/skydns/server/backend.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import "github.com/skynetservices/skydns/msg"
|
||||
|
||||
type Backend interface {
|
||||
Records(name string, exact bool) ([]msg.Service, error)
|
||||
ReverseRecord(name string) (*msg.Service, error)
|
||||
}
|
||||
|
||||
// FirstBackend exposes the Backend interface over multiple Backends, returning
|
||||
// the first Backend that answers the provided record request. If no Backend answers
|
||||
// a record request, the last error seen will be returned.
|
||||
type FirstBackend []Backend
|
||||
|
||||
// FirstBackend implements Backend
|
||||
var _ Backend = FirstBackend{}
|
||||
|
||||
func (g FirstBackend) Records(name string, exact bool) (records []msg.Service, err error) {
|
||||
var lastError error
|
||||
for _, backend := range g {
|
||||
if records, err = backend.Records(name, exact); err == nil && len(records) > 0 {
|
||||
return records, nil
|
||||
}
|
||||
if err != nil {
|
||||
lastError = err
|
||||
}
|
||||
}
|
||||
return nil, lastError
|
||||
}
|
||||
|
||||
func (g FirstBackend) ReverseRecord(name string) (record *msg.Service, err error) {
|
||||
var lastError error
|
||||
for _, backend := range g {
|
||||
if record, err = backend.ReverseRecord(name); err == nil && record != nil {
|
||||
return record, nil
|
||||
}
|
||||
if err != nil {
|
||||
lastError = err
|
||||
}
|
||||
}
|
||||
return nil, lastError
|
||||
}
|
157
vendor/github.com/skynetservices/skydns/server/config.go
generated
vendored
157
vendor/github.com/skynetservices/skydns/server/config.go
generated
vendored
@ -1,157 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const (
|
||||
SCacheCapacity = 10000
|
||||
RCacheCapacity = 100000
|
||||
RCacheTtl = 60
|
||||
)
|
||||
|
||||
// Config provides options to the SkyDNS resolver.
|
||||
type Config struct {
|
||||
// The ip:port SkyDNS should be listening on for incoming DNS requests.
|
||||
DnsAddr string `json:"dns_addr,omitempty"`
|
||||
// bind to port(s) activated by systemd. If set to true, this overrides DnsAddr.
|
||||
Systemd bool `json:"systemd,omitempty"`
|
||||
// The domain SkyDNS is authoritative for, defaults to skydns.local.
|
||||
Domain string `json:"domain,omitempty"`
|
||||
// Domain pointing to a key where service info is stored when being queried
|
||||
// for local.dns.skydns.local.
|
||||
Local string `json:"local,omitempty"`
|
||||
// The hostmaster responsible for this domain, defaults to hostmaster.<Domain>.
|
||||
Hostmaster string `json:"hostmaster,omitempty"`
|
||||
DNSSEC string `json:"dnssec,omitempty"`
|
||||
// Round robin A/AAAA replies. Default is true.
|
||||
RoundRobin bool `json:"round_robin,omitempty"`
|
||||
// Round robin selection of nameservers from among those listed, rather than have all forwarded requests try the first listed server first every time.
|
||||
NSRotate bool `json:"ns_rotate,omitempty"`
|
||||
// List of ip:port, separated by commas of recursive nameservers to forward queries to.
|
||||
Nameservers []string `json:"nameservers,omitempty"`
|
||||
// Never provide a recursive service.
|
||||
NoRec bool `json:"no_rec,omitempty"`
|
||||
ReadTimeout time.Duration `json:"read_timeout,omitempty"`
|
||||
// Default priority on SRV records when none is given. Defaults to 10.
|
||||
Priority uint16 `json:"priority"`
|
||||
// Default TTL, in seconds, when none is given in etcd. Defaults to 3600.
|
||||
Ttl uint32 `json:"ttl,omitempty"`
|
||||
// Minimum TTL, in seconds, for NXDOMAIN responses. Defaults to 300.
|
||||
MinTtl uint32 `json:"min_ttl,omitempty"`
|
||||
// SCache, capacity of the signature cache in signatures stored.
|
||||
SCache int `json:"scache,omitempty"`
|
||||
// RCache, capacity of response cache in resource records stored.
|
||||
RCache int `json:"rcache,omitempty"`
|
||||
// RCacheTtl, how long to cache in seconds.
|
||||
RCacheTtl int `json:"rcache_ttl,omitempty"`
|
||||
// How many labels a name should have before we allow forwarding. Default to 2.
|
||||
Ndots int `json:"ndot,omitempty"`
|
||||
|
||||
// DNSSEC key material
|
||||
PubKey *dns.DNSKEY `json:"-"`
|
||||
KeyTag uint16 `json:"-"`
|
||||
PrivKey crypto.Signer `json:"-"`
|
||||
|
||||
Verbose bool `json:"-"`
|
||||
|
||||
Version bool
|
||||
|
||||
// some predefined string "constants"
|
||||
localDomain string // "local.dns." + config.Domain
|
||||
dnsDomain string // "ns.dns". + config.Domain
|
||||
|
||||
// Stub zones support. Pointer to a map that we refresh when we see
|
||||
// an update. Map contains domainname -> nameserver:port
|
||||
stub *map[string][]string
|
||||
}
|
||||
|
||||
func SetDefaults(config *Config) error {
|
||||
if config.ReadTimeout == 0 {
|
||||
config.ReadTimeout = 2 * time.Second
|
||||
}
|
||||
if config.DnsAddr == "" {
|
||||
config.DnsAddr = "127.0.0.1:53"
|
||||
}
|
||||
if config.Domain == "" {
|
||||
config.Domain = "skydns.local."
|
||||
}
|
||||
if config.Hostmaster == "" {
|
||||
config.Hostmaster = appendDomain("hostmaster", config.Domain)
|
||||
}
|
||||
// People probably don't know that SOA's email addresses cannot
|
||||
// contain @-signs, replace them with dots
|
||||
config.Hostmaster = dns.Fqdn(strings.Replace(config.Hostmaster, "@", ".", -1))
|
||||
if config.MinTtl == 0 {
|
||||
config.MinTtl = 60
|
||||
}
|
||||
if config.Ttl == 0 {
|
||||
config.Ttl = 3600
|
||||
}
|
||||
if config.Priority == 0 {
|
||||
config.Priority = 10
|
||||
}
|
||||
if config.RCache < 0 {
|
||||
config.RCache = 0
|
||||
}
|
||||
if config.SCache < 0 {
|
||||
config.SCache = 0
|
||||
}
|
||||
if config.RCacheTtl == 0 {
|
||||
config.RCacheTtl = RCacheTtl
|
||||
}
|
||||
if config.Ndots <= 0 {
|
||||
config.Ndots = 2
|
||||
}
|
||||
|
||||
if len(config.Nameservers) == 0 {
|
||||
c, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
if !os.IsNotExist(err) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range c.Servers {
|
||||
config.Nameservers = append(config.Nameservers, net.JoinHostPort(s, c.Port))
|
||||
}
|
||||
}
|
||||
}
|
||||
config.Domain = dns.Fqdn(strings.ToLower(config.Domain))
|
||||
if config.DNSSEC != "" {
|
||||
// For some reason the + are replaces by spaces in etcd. Re-replace them
|
||||
keyfile := strings.Replace(config.DNSSEC, " ", "+", -1)
|
||||
k, p, err := ParseKeyFile(keyfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if k.Header().Name != dns.Fqdn(config.Domain) {
|
||||
return fmt.Errorf("ownername of DNSKEY must match SkyDNS domain")
|
||||
}
|
||||
k.Header().Ttl = config.Ttl
|
||||
config.PubKey = k
|
||||
config.KeyTag = k.KeyTag()
|
||||
config.PrivKey = p
|
||||
}
|
||||
config.localDomain = appendDomain("local.dns", config.Domain)
|
||||
config.dnsDomain = appendDomain("ns.dns", config.Domain)
|
||||
stubmap := make(map[string][]string)
|
||||
config.stub = &stubmap
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendDomain(s1, s2 string) string {
|
||||
if len(s2) > 0 && s2[0] == '.' {
|
||||
return s1 + s2
|
||||
}
|
||||
return s1 + "." + s2
|
||||
}
|
177
vendor/github.com/skynetservices/skydns/server/dnssec.go
generated
vendored
177
vendor/github.com/skynetservices/skydns/server/dnssec.go
generated
vendored
@ -1,177 +0,0 @@
|
||||
// Copyright (c) 2013 Erik St. Martin, Brian Ketelsen. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/skynetservices/skydns/cache"
|
||||
"github.com/skynetservices/skydns/metrics"
|
||||
"github.com/skynetservices/skydns/singleflight"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
var (
|
||||
inflight = &singleflight.Group{}
|
||||
)
|
||||
|
||||
|
||||
// ParseKeyFile read a DNSSEC keyfile as generated by dnssec-keygen or other
|
||||
// utilities. It add ".key" for the public key and ".private" for the private key.
|
||||
func ParseKeyFile(file string) (*dns.DNSKEY, crypto.Signer, error) {
|
||||
f, e := os.Open(file + ".key")
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
k, e := dns.ReadRR(f, file+".key")
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
f, e = os.Open(file + ".private")
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
p, e := k.(*dns.DNSKEY).ReadPrivateKey(f, file+".private")
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
|
||||
if v, ok := p.(*rsa.PrivateKey); ok {
|
||||
return k.(*dns.DNSKEY), v, nil
|
||||
}
|
||||
if v, ok := p.(*ecdsa.PrivateKey); ok {
|
||||
return k.(*dns.DNSKEY), v, nil
|
||||
}
|
||||
return k.(*dns.DNSKEY), nil, nil
|
||||
}
|
||||
|
||||
// Sign signs a message m, it takes care of negative or nodata responses as
|
||||
// well by synthesising NSEC3 records. It will also cache the signatures, using
|
||||
// a hash of the signed data as a key.
|
||||
// We also fake the origin TTL in the signature, because we don't want to
|
||||
// throw away signatures when services decide to have longer TTL. So we just
|
||||
// set the origTTL to 60.
|
||||
// TODO(miek): revisit origTTL
|
||||
func (s *server) Sign(m *dns.Msg, bufsize uint16) {
|
||||
now := time.Now().UTC()
|
||||
incep := uint32(now.Add(-3 * time.Hour).Unix()) // 2+1 hours, be sure to catch daylight saving time and such
|
||||
expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week
|
||||
|
||||
for _, r := range rrSets(m.Answer) {
|
||||
if r[0].Header().Rrtype == dns.TypeRRSIG {
|
||||
continue
|
||||
}
|
||||
if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
|
||||
continue
|
||||
}
|
||||
if sig, err := s.signSet(r, now, incep, expir); err == nil {
|
||||
m.Answer = append(m.Answer, sig)
|
||||
}
|
||||
}
|
||||
for _, r := range rrSets(m.Ns) {
|
||||
if r[0].Header().Rrtype == dns.TypeRRSIG {
|
||||
continue
|
||||
}
|
||||
if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
|
||||
continue
|
||||
}
|
||||
if sig, err := s.signSet(r, now, incep, expir); err == nil {
|
||||
m.Ns = append(m.Ns, sig)
|
||||
}
|
||||
}
|
||||
for _, r := range rrSets(m.Extra) {
|
||||
if r[0].Header().Rrtype == dns.TypeRRSIG || r[0].Header().Rrtype == dns.TypeOPT {
|
||||
continue
|
||||
}
|
||||
if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
|
||||
continue
|
||||
}
|
||||
if sig, err := s.signSet(r, now, incep, expir); err == nil {
|
||||
m.Extra = append(m.Extra, sig)
|
||||
}
|
||||
}
|
||||
|
||||
o := new(dns.OPT)
|
||||
o.Hdr.Name = "."
|
||||
o.Hdr.Rrtype = dns.TypeOPT
|
||||
o.SetDo()
|
||||
o.SetUDPSize(4096) // TODO(miek): echo client
|
||||
m.Extra = append(m.Extra, o)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *server) signSet(r []dns.RR, now time.Time, incep, expir uint32) (*dns.RRSIG, error) {
|
||||
key := cache.KeyRRset(r)
|
||||
if m, exp, hit := s.scache.Search(key); hit { // There can only be one sig in this cache.
|
||||
// Is it still valid 24 hours from now?
|
||||
if now.Add(+24*time.Hour).Sub(exp) < -24*time.Hour {
|
||||
return m.Answer[0].(*dns.RRSIG), nil
|
||||
}
|
||||
s.scache.Remove(key)
|
||||
}
|
||||
if s.config.Verbose {
|
||||
logf("scache miss for %s type %d", r[0].Header().Name, r[0].Header().Rrtype)
|
||||
}
|
||||
|
||||
metrics.ReportCacheMiss("signature")
|
||||
|
||||
sig, err := inflight.Do(key, func() (interface{}, error) {
|
||||
sig1 := s.NewRRSIG(incep, expir)
|
||||
sig1.Header().Ttl = r[0].Header().Ttl
|
||||
if r[0].Header().Rrtype == dns.TypeTXT {
|
||||
sig1.OrigTtl = 0
|
||||
}
|
||||
e := sig1.Sign(s.config.PrivKey, r)
|
||||
if e != nil {
|
||||
logf("failed to sign: %s", e.Error())
|
||||
}
|
||||
return sig1, e
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.scache.InsertSignature(key, sig.(*dns.RRSIG))
|
||||
return dns.Copy(sig.(*dns.RRSIG)).(*dns.RRSIG), nil
|
||||
}
|
||||
|
||||
func (s *server) NewRRSIG(incep, expir uint32) *dns.RRSIG {
|
||||
sig := new(dns.RRSIG)
|
||||
sig.Hdr.Rrtype = dns.TypeRRSIG
|
||||
sig.Hdr.Ttl = s.config.Ttl
|
||||
sig.OrigTtl = s.config.Ttl
|
||||
sig.Algorithm = s.config.PubKey.Algorithm
|
||||
sig.KeyTag = s.config.KeyTag
|
||||
sig.Inception = incep
|
||||
sig.Expiration = expir
|
||||
sig.SignerName = s.config.PubKey.Hdr.Name
|
||||
return sig
|
||||
}
|
||||
|
||||
type rrset struct {
|
||||
qname string
|
||||
qtype uint16
|
||||
}
|
||||
|
||||
func rrSets(rrs []dns.RR) map[rrset][]dns.RR {
|
||||
m := make(map[rrset][]dns.RR)
|
||||
for _, r := range rrs {
|
||||
if s, ok := m[rrset{r.Header().Name, r.Header().Rrtype}]; ok {
|
||||
s = append(s, r)
|
||||
m[rrset{r.Header().Name, r.Header().Rrtype}] = s
|
||||
} else {
|
||||
s := make([]dns.RR, 1, 3)
|
||||
s[0] = r
|
||||
m[rrset{r.Header().Name, r.Header().Rrtype}] = s
|
||||
}
|
||||
}
|
||||
if len(m) > 0 {
|
||||
return m
|
||||
}
|
||||
return nil
|
||||
}
|
8
vendor/github.com/skynetservices/skydns/server/doc.go
generated
vendored
8
vendor/github.com/skynetservices/skydns/server/doc.go
generated
vendored
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Package server provides a DNS server implementation that handles DNS
|
||||
// queries. To answer a query, the server asks the provided Backend for
|
||||
// DNS records, which are then converted to the proper answers.
|
||||
package server
|
34
vendor/github.com/skynetservices/skydns/server/exchange.go
generated
vendored
34
vendor/github.com/skynetservices/skydns/server/exchange.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// exchangeMsg returns a new dns message based on name, type, bufsize and dnssec.
|
||||
func newExchangeMsg(name string, typ, bufsize uint16, dnssec bool) *dns.Msg {
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(name, typ)
|
||||
m.SetEdns0(bufsize, dnssec)
|
||||
return m
|
||||
}
|
||||
|
||||
// exchangeWithRetry sends message m to server, but retries on ServerFailure.
|
||||
func exchangeWithRetry(c *dns.Client, m *dns.Msg, server string) (*dns.Msg, error) {
|
||||
r, _, err := c.Exchange(m, server)
|
||||
if err == nil && r.Rcode == dns.RcodeServerFailure {
|
||||
// redo the query
|
||||
r, _, err = c.Exchange(m, server)
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (s *server) randomNameserverID(id uint16) int {
|
||||
nsid := 0
|
||||
if s.config.NSRotate {
|
||||
// Use request Id for "random" nameserver selection.
|
||||
nsid = int(id) % len(s.config.Nameservers)
|
||||
}
|
||||
return nsid
|
||||
}
|
125
vendor/github.com/skynetservices/skydns/server/forwarding.go
generated
vendored
125
vendor/github.com/skynetservices/skydns/server/forwarding.go
generated
vendored
@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ServeDNSForward forwards a request to a nameservers and returns the response.
|
||||
func (s *server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) *dns.Msg {
|
||||
if s.config.NoRec {
|
||||
m := s.ServerFailure(req)
|
||||
w.WriteMsg(m)
|
||||
return m
|
||||
}
|
||||
|
||||
if len(s.config.Nameservers) == 0 || dns.CountLabel(req.Question[0].Name) < s.config.Ndots {
|
||||
if s.config.Verbose {
|
||||
if len(s.config.Nameservers) == 0 {
|
||||
logf("can not forward, no nameservers defined")
|
||||
} else {
|
||||
logf("can not forward, name too short (less than %d labels): `%s'", s.config.Ndots, req.Question[0].Name)
|
||||
}
|
||||
}
|
||||
m := s.ServerFailure(req)
|
||||
m.RecursionAvailable = true // this is still true
|
||||
w.WriteMsg(m)
|
||||
return m
|
||||
}
|
||||
|
||||
var (
|
||||
r *dns.Msg
|
||||
err error
|
||||
)
|
||||
|
||||
nsid := s.randomNameserverID(req.Id)
|
||||
try := 0
|
||||
Redo:
|
||||
if isTCP(w) {
|
||||
r, err = exchangeWithRetry(s.dnsTCPclient, req, s.config.Nameservers[nsid])
|
||||
} else {
|
||||
r, err = exchangeWithRetry(s.dnsUDPclient, req, s.config.Nameservers[nsid])
|
||||
}
|
||||
if err == nil {
|
||||
r.Compress = true
|
||||
r.Id = req.Id
|
||||
w.WriteMsg(r)
|
||||
return r
|
||||
}
|
||||
// Seen an error, this can only mean, "server not reached", try again
|
||||
// but only if we have not exausted our nameservers.
|
||||
if try < len(s.config.Nameservers) {
|
||||
try++
|
||||
nsid = (nsid + 1) % len(s.config.Nameservers)
|
||||
goto Redo
|
||||
}
|
||||
|
||||
logf("failure to forward request %q", err)
|
||||
m := s.ServerFailure(req)
|
||||
return m
|
||||
}
|
||||
|
||||
// ServeDNSReverse is the handler for DNS requests for the reverse zone. If nothing is found
|
||||
// locally the request is forwarded to the forwarder for resolution.
|
||||
func (s *server) ServeDNSReverse(w dns.ResponseWriter, req *dns.Msg) *dns.Msg {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
m.Compress = true
|
||||
m.Authoritative = false // Set to false, because I don't know what to do wrt DNSSEC.
|
||||
m.RecursionAvailable = true
|
||||
var err error
|
||||
if m.Answer, err = s.PTRRecords(req.Question[0]); err == nil {
|
||||
// TODO(miek): Reverse DNSSEC. We should sign this, but requires a key....and more
|
||||
// Probably not worth the hassle?
|
||||
if err := w.WriteMsg(m); err != nil {
|
||||
logf("failure to return reply %q", err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
// Always forward if not found locally.
|
||||
return s.ServeDNSForward(w, req)
|
||||
}
|
||||
|
||||
// Lookup looks up name,type using the recursive nameserver defines
|
||||
// in the server's config. If none defined it returns an error.
|
||||
func (s *server) Lookup(n string, t, bufsize uint16, dnssec bool) (*dns.Msg, error) {
|
||||
if len(s.config.Nameservers) == 0 {
|
||||
return nil, fmt.Errorf("no nameservers configured can not lookup name")
|
||||
}
|
||||
if dns.CountLabel(n) < s.config.Ndots {
|
||||
return nil, fmt.Errorf("name has fewer than %d labels", s.config.Ndots)
|
||||
}
|
||||
m := newExchangeMsg(n, t, bufsize, dnssec)
|
||||
|
||||
nsid := s.randomNameserverID(m.Id)
|
||||
try := 0
|
||||
Redo:
|
||||
r, err := exchangeWithRetry(s.dnsUDPclient, m, s.config.Nameservers[nsid])
|
||||
if err == nil {
|
||||
if r.Rcode != dns.RcodeSuccess {
|
||||
return nil, fmt.Errorf("rcode %d is not equal to success", r.Rcode)
|
||||
}
|
||||
// Reset TTLs to rcache TTL to make some of the other code
|
||||
// and the tests not care about TTLs
|
||||
for _, rr := range r.Answer {
|
||||
rr.Header().Ttl = uint32(s.config.RCacheTtl)
|
||||
}
|
||||
for _, rr := range r.Extra {
|
||||
rr.Header().Ttl = uint32(s.config.RCacheTtl)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
// Seen an error, this can only mean, "server not reached", try again
|
||||
// but only if we have not exausted our nameservers.
|
||||
if try < len(s.config.Nameservers) {
|
||||
try++
|
||||
nsid = (nsid + 1) % len(s.config.Nameservers)
|
||||
goto Redo
|
||||
}
|
||||
return nil, fmt.Errorf("failure to lookup name")
|
||||
}
|
17
vendor/github.com/skynetservices/skydns/server/log.go
generated
vendored
17
vendor/github.com/skynetservices/skydns/server/log.go
generated
vendored
@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import "log"
|
||||
|
||||
// printf calls log.Printf with the parameters given.
|
||||
func logf(format string, a ...interface{}) {
|
||||
log.Printf("skydns: "+format, a...)
|
||||
}
|
||||
|
||||
// fatalf calls log.Fatalf with the parameters given.
|
||||
func fatalf(format string, a ...interface{}) {
|
||||
log.Fatalf("skydns: "+format, a...)
|
||||
}
|
54
vendor/github.com/skynetservices/skydns/server/msg.go
generated
vendored
54
vendor/github.com/skynetservices/skydns/server/msg.go
generated
vendored
@ -1,54 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// Fit will make m fit the size. If a message is larger than size then entire
|
||||
// additional section is dropped. If it is still to large and the transport
|
||||
// is udp we return a truncated message.
|
||||
// If the transport is tcp we are going to drop RR from the answer section
|
||||
// until it fits. When this is case the returned bool is true.
|
||||
func Fit(m *dns.Msg, size int, tcp bool) (*dns.Msg, bool) {
|
||||
if m.Len() > size {
|
||||
// Check for OPT Records at the end and keep those. TODO(miek)
|
||||
m.Extra = nil
|
||||
}
|
||||
if m.Len() < size {
|
||||
return m, false
|
||||
}
|
||||
|
||||
// With TCP setting TC does not mean anything.
|
||||
if !tcp {
|
||||
m.Truncated = true
|
||||
// fall through here, so we at least return a message that can
|
||||
// fit the udp buffer.
|
||||
}
|
||||
|
||||
// Additional section is gone, binary search until we have length that fits.
|
||||
min, max := 0, len(m.Answer)
|
||||
original := make([]dns.RR, len(m.Answer))
|
||||
copy(original, m.Answer)
|
||||
for {
|
||||
if min == max {
|
||||
break
|
||||
}
|
||||
|
||||
mid := (min + max) / 2
|
||||
m.Answer = original[:mid]
|
||||
|
||||
if m.Len() < size {
|
||||
min++
|
||||
continue
|
||||
}
|
||||
max = mid
|
||||
|
||||
}
|
||||
if max > 1 {
|
||||
max--
|
||||
}
|
||||
m.Answer = m.Answer[:max]
|
||||
return m, true
|
||||
}
|
155
vendor/github.com/skynetservices/skydns/server/nsec3.go
generated
vendored
155
vendor/github.com/skynetservices/skydns/server/nsec3.go
generated
vendored
@ -1,155 +0,0 @@
|
||||
// Copyright (c) 2013 Erik St. Martin, Brian Ketelsen. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Do DNSSEC NXDOMAIN with NSEC3 whitelies: rfc 7129, appendix B.
|
||||
// The closest encloser will be qname - the left most label and the
|
||||
// next closer will be the full qname which we then will deny.
|
||||
// Idem for source of synthesis.
|
||||
|
||||
func (s *server) Denial(m *dns.Msg) {
|
||||
if m.Rcode == dns.RcodeNameError {
|
||||
// ce is qname minus the left label
|
||||
idx := dns.Split(m.Question[0].Name)
|
||||
ce := m.Question[0].Name[idx[1]:]
|
||||
|
||||
nsec3ce, nsec3wildcard := newNSEC3CEandWildcard(s.config.Domain, ce, s.config.MinTtl)
|
||||
// Add ce and wildcard
|
||||
m.Ns = append(m.Ns, nsec3ce)
|
||||
m.Ns = append(m.Ns, nsec3wildcard)
|
||||
// Deny Qname nsec3
|
||||
m.Ns = append(m.Ns, s.newNSEC3NameError(m.Question[0].Name))
|
||||
}
|
||||
if m.Rcode == dns.RcodeSuccess && len(m.Ns) == 1 {
|
||||
// NODATA
|
||||
if _, ok := m.Ns[0].(*dns.SOA); ok {
|
||||
m.Ns = append(m.Ns, s.newNSEC3NoData(m.Question[0].Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func packBase32(s string) []byte {
|
||||
b32len := base32.HexEncoding.DecodedLen(len(s))
|
||||
buf := make([]byte, b32len)
|
||||
n, _ := base32.HexEncoding.Decode(buf, []byte(s))
|
||||
buf = buf[:n]
|
||||
return buf
|
||||
}
|
||||
|
||||
func unpackBase32(b []byte) string {
|
||||
b32 := make([]byte, base32.HexEncoding.EncodedLen(len(b)))
|
||||
base32.HexEncoding.Encode(b32, b)
|
||||
return string(b32)
|
||||
}
|
||||
|
||||
// newNSEC3NameError returns the NSEC3 record needed to denial qname.
|
||||
func (s *server) newNSEC3NameError(qname string) *dns.NSEC3 {
|
||||
n := new(dns.NSEC3)
|
||||
n.Hdr.Class = dns.ClassINET
|
||||
n.Hdr.Rrtype = dns.TypeNSEC3
|
||||
n.Hdr.Ttl = s.config.MinTtl
|
||||
n.Hash = dns.SHA1
|
||||
n.Flags = 0
|
||||
n.Salt = ""
|
||||
n.TypeBitMap = []uint16{}
|
||||
|
||||
covername := dns.HashName(qname, dns.SHA1, 0, "")
|
||||
|
||||
buf := packBase32(covername)
|
||||
byteArith(buf, false) // one before
|
||||
n.Hdr.Name = appendDomain(strings.ToLower(unpackBase32(buf)), s.config.Domain)
|
||||
byteArith(buf, true) // one next
|
||||
byteArith(buf, true) // and another one
|
||||
n.NextDomain = unpackBase32(buf)
|
||||
return n
|
||||
}
|
||||
|
||||
// newNSEC3NoData returns the NSEC3 record needed to denial the types
|
||||
func (s *server) newNSEC3NoData(qname string) *dns.NSEC3 {
|
||||
n := new(dns.NSEC3)
|
||||
n.Hdr.Class = dns.ClassINET
|
||||
n.Hdr.Rrtype = dns.TypeNSEC3
|
||||
n.Hdr.Ttl = s.config.MinTtl
|
||||
n.Hash = dns.SHA1
|
||||
n.Flags = 0
|
||||
n.Salt = ""
|
||||
n.TypeBitMap = []uint16{dns.TypeA, dns.TypeAAAA, dns.TypeSRV, dns.TypeRRSIG}
|
||||
|
||||
n.Hdr.Name = dns.HashName(qname, dns.SHA1, 0, "")
|
||||
buf := packBase32(n.Hdr.Name)
|
||||
byteArith(buf, true) // one next
|
||||
n.NextDomain = unpackBase32(buf)
|
||||
|
||||
n.Hdr.Name += appendDomain("", s.config.Domain)
|
||||
return n
|
||||
}
|
||||
|
||||
// newNSEC3CEandWildcard returns the NSEC3 for the closest encloser
|
||||
// and the NSEC3 that denies that wildcard at that level.
|
||||
func newNSEC3CEandWildcard(apex, ce string, ttl uint32) (*dns.NSEC3, *dns.NSEC3) {
|
||||
n1 := new(dns.NSEC3)
|
||||
n1.Hdr.Class = dns.ClassINET
|
||||
n1.Hdr.Rrtype = dns.TypeNSEC3
|
||||
n1.Hdr.Ttl = ttl
|
||||
n1.Hash = dns.SHA1
|
||||
n1.Flags = 0
|
||||
n1.Iterations = 0
|
||||
n1.Salt = ""
|
||||
// for the apex we need another bitmap
|
||||
n1.TypeBitMap = []uint16{dns.TypeA, dns.TypeAAAA, dns.TypeSRV, dns.TypeRRSIG}
|
||||
prev := dns.HashName(ce, dns.SHA1, n1.Iterations, n1.Salt)
|
||||
n1.Hdr.Name = strings.ToLower(prev) + "." + apex
|
||||
buf := packBase32(prev)
|
||||
byteArith(buf, true) // one next
|
||||
n1.NextDomain = unpackBase32(buf)
|
||||
|
||||
n2 := new(dns.NSEC3)
|
||||
n2.Hdr.Class = dns.ClassINET
|
||||
n2.Hdr.Rrtype = dns.TypeNSEC3
|
||||
n2.Hdr.Ttl = ttl
|
||||
n2.Hash = dns.SHA1
|
||||
n2.Flags = 0
|
||||
n2.Iterations = 0
|
||||
n2.Salt = ""
|
||||
|
||||
prev = dns.HashName("*."+ce, dns.SHA1, n2.Iterations, n2.Salt)
|
||||
buf = packBase32(prev)
|
||||
byteArith(buf, false) // one before
|
||||
n2.Hdr.Name = appendDomain(strings.ToLower(unpackBase32(buf)), apex)
|
||||
byteArith(buf, true) // one next
|
||||
byteArith(buf, true) // and another one
|
||||
n2.NextDomain = unpackBase32(buf)
|
||||
|
||||
return n1, n2
|
||||
}
|
||||
|
||||
// byteArith adds either 1 or -1 to b, there is no check for under- or overflow.
|
||||
func byteArith(b []byte, x bool) {
|
||||
if x {
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
if b[i] == 255 {
|
||||
b[i] = 0
|
||||
continue
|
||||
}
|
||||
b[i]++
|
||||
return
|
||||
}
|
||||
}
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
if b[i] == 0 {
|
||||
b[i] = 255
|
||||
continue
|
||||
}
|
||||
b[i]--
|
||||
return
|
||||
}
|
||||
}
|
889
vendor/github.com/skynetservices/skydns/server/server.go
generated
vendored
889
vendor/github.com/skynetservices/skydns/server/server.go
generated
vendored
@ -1,889 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/skynetservices/skydns/cache"
|
||||
"github.com/skynetservices/skydns/metrics"
|
||||
"github.com/skynetservices/skydns/msg"
|
||||
|
||||
etcd "github.com/coreos/etcd/client"
|
||||
"github.com/coreos/go-systemd/activation"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const Version = "2.5.3a"
|
||||
|
||||
type server struct {
|
||||
backend Backend
|
||||
config *Config
|
||||
|
||||
group *sync.WaitGroup
|
||||
dnsUDPclient *dns.Client // used for forwarding queries
|
||||
dnsTCPclient *dns.Client // used for forwarding queries
|
||||
scache *cache.Cache
|
||||
rcache *cache.Cache
|
||||
}
|
||||
|
||||
// New returns a new SkyDNS server.
|
||||
func New(backend Backend, config *Config) *server {
|
||||
return &server{
|
||||
backend: backend,
|
||||
config: config,
|
||||
|
||||
group: new(sync.WaitGroup),
|
||||
scache: cache.New(config.SCache, 0),
|
||||
rcache: cache.New(config.RCache, config.RCacheTtl),
|
||||
dnsUDPclient: &dns.Client{Net: "udp", ReadTimeout: config.ReadTimeout, WriteTimeout: config.ReadTimeout, SingleInflight: true},
|
||||
dnsTCPclient: &dns.Client{Net: "tcp", ReadTimeout: config.ReadTimeout, WriteTimeout: config.ReadTimeout, SingleInflight: true},
|
||||
}
|
||||
}
|
||||
|
||||
// Run is a blocking operation that starts the server listening on the DNS ports.
|
||||
func (s *server) Run() error {
|
||||
mux := dns.NewServeMux()
|
||||
mux.Handle(".", s)
|
||||
|
||||
dnsReadyMsg := func(addr, net string) {
|
||||
if s.config.DNSSEC == "" {
|
||||
logf("ready for queries on %s for %s://%s [rcache %d]", s.config.Domain, net, addr, s.config.RCache)
|
||||
} else {
|
||||
logf("ready for queries on %s for %s://%s [rcache %d], signing with %s [scache %d]", s.config.Domain, net, addr, s.config.RCache, s.config.DNSSEC, s.config.SCache)
|
||||
}
|
||||
}
|
||||
|
||||
if s.config.Systemd {
|
||||
packetConns, err := activation.PacketConns(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listeners, err := activation.Listeners(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(packetConns) == 0 && len(listeners) == 0 {
|
||||
return fmt.Errorf("no UDP or TCP sockets supplied by systemd")
|
||||
}
|
||||
for _, p := range packetConns {
|
||||
if u, ok := p.(*net.UDPConn); ok {
|
||||
s.group.Add(1)
|
||||
go func() {
|
||||
defer s.group.Done()
|
||||
if err := dns.ActivateAndServe(nil, u, mux); err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
}()
|
||||
dnsReadyMsg(u.LocalAddr().String(), "udp")
|
||||
}
|
||||
}
|
||||
for _, l := range listeners {
|
||||
if t, ok := l.(*net.TCPListener); ok {
|
||||
s.group.Add(1)
|
||||
go func() {
|
||||
defer s.group.Done()
|
||||
if err := dns.ActivateAndServe(t, nil, mux); err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
}()
|
||||
dnsReadyMsg(t.Addr().String(), "tcp")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.group.Add(1)
|
||||
go func() {
|
||||
defer s.group.Done()
|
||||
if err := dns.ListenAndServe(s.config.DnsAddr, "tcp", mux); err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
}()
|
||||
dnsReadyMsg(s.config.DnsAddr, "tcp")
|
||||
s.group.Add(1)
|
||||
go func() {
|
||||
defer s.group.Done()
|
||||
if err := dns.ListenAndServe(s.config.DnsAddr, "udp", mux); err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
}()
|
||||
dnsReadyMsg(s.config.DnsAddr, "udp")
|
||||
}
|
||||
|
||||
s.group.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops a server.
|
||||
func (s *server) Stop() {
|
||||
// TODO(miek)
|
||||
//s.group.Add(-2)
|
||||
}
|
||||
|
||||
// ServeDNS is the handler for DNS requests, responsible for parsing DNS request, possibly forwarding
|
||||
// it to a real dns server and returning a response.
|
||||
func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
m.Authoritative = true
|
||||
m.RecursionAvailable = true
|
||||
m.Compress = true
|
||||
|
||||
bufsize := uint16(512)
|
||||
dnssec := false
|
||||
tcp := false
|
||||
start := time.Now()
|
||||
|
||||
q := req.Question[0]
|
||||
name := strings.ToLower(q.Name)
|
||||
|
||||
if q.Qtype == dns.TypeANY {
|
||||
m.Authoritative = false
|
||||
m.Rcode = dns.RcodeRefused
|
||||
m.RecursionAvailable = false
|
||||
m.RecursionDesired = false
|
||||
m.Compress = false
|
||||
w.WriteMsg(m)
|
||||
|
||||
metrics.ReportRequestCount(m, metrics.Auth)
|
||||
metrics.ReportDuration(m, start, metrics.Auth)
|
||||
metrics.ReportErrorCount(m, metrics.Auth)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if o := req.IsEdns0(); o != nil {
|
||||
bufsize = o.UDPSize()
|
||||
dnssec = o.Do()
|
||||
}
|
||||
if bufsize < 512 {
|
||||
bufsize = 512
|
||||
}
|
||||
// with TCP we can send 64K
|
||||
if tcp = isTCP(w); tcp {
|
||||
bufsize = dns.MaxMsgSize - 1
|
||||
}
|
||||
|
||||
if s.config.Verbose {
|
||||
logf("received DNS Request for %q from %q with type %d", q.Name, w.RemoteAddr(), q.Qtype)
|
||||
}
|
||||
|
||||
// Check cache first.
|
||||
m1 := s.rcache.Hit(q, dnssec, tcp, m.Id)
|
||||
if m1 != nil {
|
||||
metrics.ReportRequestCount(req, metrics.Cache)
|
||||
|
||||
if send := s.overflowOrTruncated(w, m1, int(bufsize), metrics.Cache); send {
|
||||
return
|
||||
}
|
||||
|
||||
// Still round-robin even with hits from the cache.
|
||||
// Only shuffle A and AAAA records with each other.
|
||||
if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA {
|
||||
s.RoundRobin(m1.Answer)
|
||||
}
|
||||
|
||||
if err := w.WriteMsg(m1); err != nil {
|
||||
logf("failure to return reply %q", err)
|
||||
}
|
||||
|
||||
metrics.ReportDuration(m1, start, metrics.Cache)
|
||||
metrics.ReportErrorCount(m1, metrics.Cache)
|
||||
return
|
||||
}
|
||||
|
||||
for zone, ns := range *s.config.stub {
|
||||
if strings.HasSuffix(name, "." + zone) || name == zone {
|
||||
metrics.ReportRequestCount(req, metrics.Stub)
|
||||
|
||||
resp := s.ServeDNSStubForward(w, req, ns)
|
||||
if resp != nil {
|
||||
s.rcache.InsertMessage(cache.Key(q, dnssec, tcp), resp)
|
||||
}
|
||||
|
||||
metrics.ReportDuration(resp, start, metrics.Stub)
|
||||
metrics.ReportErrorCount(resp, metrics.Stub)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If the qname is local.ds.skydns.local. and s.config.Local != "", substitute that name.
|
||||
if s.config.Local != "" && name == s.config.localDomain {
|
||||
name = s.config.Local
|
||||
}
|
||||
|
||||
if q.Qtype == dns.TypePTR && strings.HasSuffix(name, ".in-addr.arpa.") || strings.HasSuffix(name, ".ip6.arpa.") {
|
||||
metrics.ReportRequestCount(req, metrics.Reverse)
|
||||
|
||||
resp := s.ServeDNSReverse(w, req)
|
||||
if resp != nil {
|
||||
s.rcache.InsertMessage(cache.Key(q, dnssec, tcp), resp)
|
||||
}
|
||||
|
||||
metrics.ReportDuration(resp, start, metrics.Reverse)
|
||||
metrics.ReportErrorCount(resp, metrics.Reverse)
|
||||
return
|
||||
}
|
||||
|
||||
if q.Qclass != dns.ClassCHAOS && !strings.HasSuffix(name, "." +s.config.Domain) && name != s.config.Domain {
|
||||
metrics.ReportRequestCount(req, metrics.Rec)
|
||||
|
||||
resp := s.ServeDNSForward(w, req)
|
||||
if resp != nil {
|
||||
s.rcache.InsertMessage(cache.Key(q, dnssec, tcp), resp)
|
||||
}
|
||||
|
||||
metrics.ReportDuration(resp, start, metrics.Rec)
|
||||
metrics.ReportErrorCount(resp, metrics.Rec)
|
||||
return
|
||||
}
|
||||
|
||||
metrics.ReportCacheMiss(metrics.Response)
|
||||
|
||||
defer func() {
|
||||
metrics.ReportDuration(m, start, metrics.Auth)
|
||||
metrics.ReportErrorCount(m, metrics.Auth)
|
||||
|
||||
if m.Rcode == dns.RcodeServerFailure {
|
||||
if err := w.WriteMsg(m); err != nil {
|
||||
logf("failure to return reply %q", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Set TTL to the minimum of the RRset and dedup the message, i.e. remove identical RRs.
|
||||
m = s.dedup(m)
|
||||
|
||||
minttl := s.config.Ttl
|
||||
if len(m.Answer) > 1 {
|
||||
for _, r := range m.Answer {
|
||||
if r.Header().Ttl < minttl {
|
||||
minttl = r.Header().Ttl
|
||||
}
|
||||
}
|
||||
for _, r := range m.Answer {
|
||||
r.Header().Ttl = minttl
|
||||
}
|
||||
}
|
||||
|
||||
if dnssec {
|
||||
if s.config.PubKey != nil {
|
||||
m.AuthenticatedData = true
|
||||
s.Denial(m)
|
||||
s.Sign(m, bufsize)
|
||||
}
|
||||
}
|
||||
|
||||
if send := s.overflowOrTruncated(w, m, int(bufsize), metrics.Auth); send {
|
||||
return
|
||||
}
|
||||
|
||||
s.rcache.InsertMessage(cache.Key(q, dnssec, tcp), m)
|
||||
|
||||
if err := w.WriteMsg(m); err != nil {
|
||||
logf("failure to return reply %q", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if name == s.config.Domain {
|
||||
if q.Qtype == dns.TypeSOA {
|
||||
m.Answer = []dns.RR{s.NewSOA()}
|
||||
return
|
||||
}
|
||||
if q.Qtype == dns.TypeDNSKEY {
|
||||
if s.config.PubKey != nil {
|
||||
m.Answer = []dns.RR{s.config.PubKey}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if q.Qclass == dns.ClassCHAOS {
|
||||
if q.Qtype == dns.TypeTXT {
|
||||
switch name {
|
||||
case "authors.bind.":
|
||||
fallthrough
|
||||
case s.config.Domain:
|
||||
hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}
|
||||
authors := []string{"Erik St. Martin", "Brian Ketelsen", "Miek Gieben", "Michael Crosby"}
|
||||
for _, a := range authors {
|
||||
m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{a}})
|
||||
}
|
||||
for j := 0; j < len(authors)*(int(dns.Id())%4+1); j++ {
|
||||
q := int(dns.Id()) % len(authors)
|
||||
p := int(dns.Id()) % len(authors)
|
||||
if q == p {
|
||||
p = (p + 1) % len(authors)
|
||||
}
|
||||
m.Answer[q], m.Answer[p] = m.Answer[p], m.Answer[q]
|
||||
}
|
||||
return
|
||||
case "version.bind.":
|
||||
fallthrough
|
||||
case "version.server.":
|
||||
hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}
|
||||
m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{Version}}}
|
||||
return
|
||||
case "hostname.bind.":
|
||||
fallthrough
|
||||
case "id.server.":
|
||||
// TODO(miek): machine name to return
|
||||
hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}
|
||||
m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{"localhost"}}}
|
||||
return
|
||||
}
|
||||
}
|
||||
// still here, fail
|
||||
m.SetReply(req)
|
||||
m.SetRcode(req, dns.RcodeServerFailure)
|
||||
return
|
||||
}
|
||||
|
||||
switch q.Qtype {
|
||||
case dns.TypeNS:
|
||||
if name != s.config.Domain {
|
||||
break
|
||||
}
|
||||
// Lookup s.config.DnsDomain
|
||||
records, extra, err := s.NSRecords(q, s.config.dnsDomain)
|
||||
if isEtcdNameError(err, s) {
|
||||
m = s.NameError(req)
|
||||
return
|
||||
}
|
||||
m.Answer = append(m.Answer, records...)
|
||||
m.Extra = append(m.Extra, extra...)
|
||||
case dns.TypeA, dns.TypeAAAA:
|
||||
records, err := s.AddressRecords(q, name, nil, bufsize, dnssec, false)
|
||||
if isEtcdNameError(err, s) {
|
||||
m = s.NameError(req)
|
||||
return
|
||||
}
|
||||
m.Answer = append(m.Answer, records...)
|
||||
case dns.TypeTXT:
|
||||
records, err := s.TXTRecords(q, name)
|
||||
if isEtcdNameError(err, s) {
|
||||
m = s.NameError(req)
|
||||
return
|
||||
}
|
||||
m.Answer = append(m.Answer, records...)
|
||||
case dns.TypeCNAME:
|
||||
records, err := s.CNAMERecords(q, name)
|
||||
if isEtcdNameError(err, s) {
|
||||
m = s.NameError(req)
|
||||
return
|
||||
}
|
||||
m.Answer = append(m.Answer, records...)
|
||||
case dns.TypeMX:
|
||||
records, extra, err := s.MXRecords(q, name, bufsize, dnssec)
|
||||
if isEtcdNameError(err, s) {
|
||||
m = s.NameError(req)
|
||||
return
|
||||
}
|
||||
m.Answer = append(m.Answer, records...)
|
||||
m.Extra = append(m.Extra, extra...)
|
||||
default:
|
||||
fallthrough // also catch other types, so that they return NODATA
|
||||
case dns.TypeSRV:
|
||||
records, extra, err := s.SRVRecords(q, name, bufsize, dnssec)
|
||||
if err != nil {
|
||||
if isEtcdNameError(err, s) {
|
||||
m = s.NameError(req)
|
||||
return
|
||||
}
|
||||
logf("got error from backend: %s", err)
|
||||
if q.Qtype == dns.TypeSRV { // Otherwise NODATA
|
||||
m = s.ServerFailure(req)
|
||||
return
|
||||
}
|
||||
}
|
||||
// if we are here again, check the types, because an answer may only
|
||||
// be given for SRV. All other types should return NODATA, the
|
||||
// NXDOMAIN part is handled in the above code. TODO(miek): yes this
|
||||
// can be done in a more elegant manor.
|
||||
if q.Qtype == dns.TypeSRV {
|
||||
m.Answer = append(m.Answer, records...)
|
||||
m.Extra = append(m.Extra, extra...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.Answer) == 0 { // NODATA response
|
||||
m.Ns = []dns.RR{s.NewSOA()}
|
||||
m.Ns[0].Header().Ttl = s.config.MinTtl
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) AddressRecords(q dns.Question, name string, previousRecords []dns.RR, bufsize uint16, dnssec, both bool) (records []dns.RR, err error) {
|
||||
services, err := s.backend.Records(name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
services = msg.Group(services)
|
||||
|
||||
for _, serv := range services {
|
||||
ip := net.ParseIP(serv.Host)
|
||||
switch {
|
||||
case ip == nil:
|
||||
// Try to resolve as CNAME if it's not an IP, but only if we don't create loops.
|
||||
if q.Name == dns.Fqdn(serv.Host) {
|
||||
logf("CNAME loop detected: %q -> %q", q.Name, q.Name)
|
||||
// x CNAME x is a direct loop, don't add those
|
||||
continue
|
||||
}
|
||||
|
||||
newRecord := serv.NewCNAME(q.Name, dns.Fqdn(serv.Host))
|
||||
if len(previousRecords) > 7 {
|
||||
logf("CNAME lookup limit of 8 exceeded for %s", newRecord)
|
||||
// don't add it, and just continue
|
||||
continue
|
||||
}
|
||||
if s.isDuplicateCNAME(newRecord, previousRecords) {
|
||||
logf("CNAME loop detected for record %s", newRecord)
|
||||
continue
|
||||
}
|
||||
|
||||
nextRecords, err := s.AddressRecords(dns.Question{Name: dns.Fqdn(serv.Host), Qtype: q.Qtype, Qclass: q.Qclass},
|
||||
strings.ToLower(dns.Fqdn(serv.Host)), append(previousRecords, newRecord), bufsize, dnssec, both)
|
||||
if err == nil {
|
||||
// Only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// This means we can not complete the CNAME, try to look else where.
|
||||
target := newRecord.Target
|
||||
if dns.IsSubDomain(s.config.Domain, target) {
|
||||
// We should already have found it
|
||||
continue
|
||||
}
|
||||
m1, e1 := s.Lookup(target, q.Qtype, bufsize, dnssec)
|
||||
if e1 != nil {
|
||||
logf("incomplete CNAME chain from %q: %s", target, e1)
|
||||
continue
|
||||
}
|
||||
// Len(m1.Answer) > 0 here is well?
|
||||
records = append(records, newRecord)
|
||||
records = append(records, m1.Answer...)
|
||||
continue
|
||||
case ip.To4() != nil && (q.Qtype == dns.TypeA || both):
|
||||
records = append(records, serv.NewA(q.Name, ip.To4()))
|
||||
case ip.To4() == nil && (q.Qtype == dns.TypeAAAA || both):
|
||||
records = append(records, serv.NewAAAA(q.Name, ip.To16()))
|
||||
}
|
||||
}
|
||||
s.RoundRobin(records)
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// NSRecords returns NS records from etcd.
|
||||
func (s *server) NSRecords(q dns.Question, name string) (records []dns.RR, extra []dns.RR, err error) {
|
||||
services, err := s.backend.Records(name, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
services = msg.Group(services)
|
||||
|
||||
for _, serv := range services {
|
||||
ip := net.ParseIP(serv.Host)
|
||||
switch {
|
||||
case ip == nil:
|
||||
return nil, nil, fmt.Errorf("NS record must be an IP address")
|
||||
case ip.To4() != nil:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
records = append(records, serv.NewNS(q.Name, serv.Host))
|
||||
extra = append(extra, serv.NewA(serv.Host, ip.To4()))
|
||||
case ip.To4() == nil:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
records = append(records, serv.NewNS(q.Name, serv.Host))
|
||||
extra = append(extra, serv.NewAAAA(serv.Host, ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, extra, nil
|
||||
}
|
||||
|
||||
// SRVRecords returns SRV records from etcd.
|
||||
// If the Target is not a name but an IP address, a name is created.
|
||||
func (s *server) SRVRecords(q dns.Question, name string, bufsize uint16, dnssec bool) (records []dns.RR, extra []dns.RR, err error) {
|
||||
services, err := s.backend.Records(name, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
services = msg.Group(services)
|
||||
|
||||
// Looping twice to get the right weight vs priority
|
||||
w := make(map[int]int)
|
||||
for _, serv := range services {
|
||||
weight := 100
|
||||
if serv.Weight != 0 {
|
||||
weight = serv.Weight
|
||||
}
|
||||
if _, ok := w[serv.Priority]; !ok {
|
||||
w[serv.Priority] = weight
|
||||
continue
|
||||
}
|
||||
w[serv.Priority] += weight
|
||||
}
|
||||
lookup := make(map[string]bool)
|
||||
for _, serv := range services {
|
||||
w1 := 100.0 / float64(w[serv.Priority])
|
||||
if serv.Weight == 0 {
|
||||
w1 *= 100
|
||||
} else {
|
||||
w1 *= float64(serv.Weight)
|
||||
}
|
||||
weight := uint16(math.Floor(w1))
|
||||
ip := net.ParseIP(serv.Host)
|
||||
switch {
|
||||
case ip == nil:
|
||||
srv := serv.NewSRV(q.Name, weight)
|
||||
records = append(records, srv)
|
||||
|
||||
if _, ok := lookup[srv.Target]; ok {
|
||||
break
|
||||
}
|
||||
|
||||
lookup[srv.Target] = true
|
||||
|
||||
if !dns.IsSubDomain(s.config.Domain, srv.Target) {
|
||||
m1, e1 := s.Lookup(srv.Target, dns.TypeA, bufsize, dnssec)
|
||||
if e1 == nil {
|
||||
extra = append(extra, m1.Answer...)
|
||||
}
|
||||
m1, e1 = s.Lookup(srv.Target, dns.TypeAAAA, bufsize, dnssec)
|
||||
if e1 == nil {
|
||||
// If we have seen CNAME's we *assume* that they are already added.
|
||||
for _, a := range m1.Answer {
|
||||
if _, ok := a.(*dns.CNAME); !ok {
|
||||
extra = append(extra, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// Internal name, we should have some info on them, either v4 or v6
|
||||
// Clients expect a complete answer, because we are a recursor in their
|
||||
// view.
|
||||
addr, e1 := s.AddressRecords(dns.Question{srv.Target, dns.ClassINET, dns.TypeA},
|
||||
srv.Target, nil, bufsize, dnssec, true)
|
||||
if e1 == nil {
|
||||
extra = append(extra, addr...)
|
||||
}
|
||||
case ip.To4() != nil:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
srv := serv.NewSRV(q.Name, weight)
|
||||
|
||||
records = append(records, srv)
|
||||
extra = append(extra, serv.NewA(srv.Target, ip.To4()))
|
||||
case ip.To4() == nil:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
srv := serv.NewSRV(q.Name, weight)
|
||||
|
||||
records = append(records, srv)
|
||||
extra = append(extra, serv.NewAAAA(srv.Target, ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, extra, nil
|
||||
}
|
||||
|
||||
// MXRecords returns MX records from etcd.
|
||||
// If the Target is not a name but an IP address, a name is created.
|
||||
func (s *server) MXRecords(q dns.Question, name string, bufsize uint16, dnssec bool) (records []dns.RR, extra []dns.RR, err error) {
|
||||
services, err := s.backend.Records(name, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
lookup := make(map[string]bool)
|
||||
for _, serv := range services {
|
||||
if !serv.Mail {
|
||||
continue
|
||||
}
|
||||
ip := net.ParseIP(serv.Host)
|
||||
switch {
|
||||
case ip == nil:
|
||||
mx := serv.NewMX(q.Name)
|
||||
records = append(records, mx)
|
||||
if _, ok := lookup[mx.Mx]; ok {
|
||||
break
|
||||
}
|
||||
|
||||
lookup[mx.Mx] = true
|
||||
|
||||
if !dns.IsSubDomain(s.config.Domain, mx.Mx) {
|
||||
m1, e1 := s.Lookup(mx.Mx, dns.TypeA, bufsize, dnssec)
|
||||
if e1 == nil {
|
||||
extra = append(extra, m1.Answer...)
|
||||
}
|
||||
m1, e1 = s.Lookup(mx.Mx, dns.TypeAAAA, bufsize, dnssec)
|
||||
if e1 == nil {
|
||||
// If we have seen CNAME's we *assume* that they are already added.
|
||||
for _, a := range m1.Answer {
|
||||
if _, ok := a.(*dns.CNAME); !ok {
|
||||
extra = append(extra, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// Internal name
|
||||
addr, e1 := s.AddressRecords(dns.Question{mx.Mx, dns.ClassINET, dns.TypeA},
|
||||
mx.Mx, nil, bufsize, dnssec, true)
|
||||
if e1 == nil {
|
||||
extra = append(extra, addr...)
|
||||
}
|
||||
case ip.To4() != nil:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
records = append(records, serv.NewMX(q.Name))
|
||||
extra = append(extra, serv.NewA(serv.Host, ip.To4()))
|
||||
case ip.To4() == nil:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
records = append(records, serv.NewMX(q.Name))
|
||||
extra = append(extra, serv.NewAAAA(serv.Host, ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, extra, nil
|
||||
}
|
||||
|
||||
func (s *server) CNAMERecords(q dns.Question, name string) (records []dns.RR, err error) {
|
||||
services, err := s.backend.Records(name, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
services = msg.Group(services)
|
||||
|
||||
if len(services) > 0 {
|
||||
serv := services[0]
|
||||
if ip := net.ParseIP(serv.Host); ip == nil {
|
||||
records = append(records, serv.NewCNAME(q.Name, dns.Fqdn(serv.Host)))
|
||||
}
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (s *server) TXTRecords(q dns.Question, name string) (records []dns.RR, err error) {
|
||||
services, err := s.backend.Records(name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
services = msg.Group(services)
|
||||
|
||||
for _, serv := range services {
|
||||
if serv.Text == "" {
|
||||
continue
|
||||
}
|
||||
records = append(records, serv.NewTXT(q.Name))
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (s *server) PTRRecords(q dns.Question) (records []dns.RR, err error) {
|
||||
name := strings.ToLower(q.Name)
|
||||
serv, err := s.backend.ReverseRecord(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records = append(records, serv.NewPTR(q.Name, serv.Ttl))
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// SOA returns a SOA record for this SkyDNS instance.
|
||||
func (s *server) NewSOA() dns.RR {
|
||||
return &dns.SOA{Hdr: dns.RR_Header{Name: s.config.Domain, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: s.config.Ttl},
|
||||
Ns: appendDomain("ns.dns", s.config.Domain),
|
||||
Mbox: s.config.Hostmaster,
|
||||
Serial: uint32(time.Now().Truncate(time.Hour).Unix()),
|
||||
Refresh: 28800,
|
||||
Retry: 7200,
|
||||
Expire: 604800,
|
||||
Minttl: s.config.MinTtl,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
||||
for _, rec := range records {
|
||||
if v, ok := rec.(*dns.CNAME); ok {
|
||||
if v.Target == r.Target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *server) NameError(req *dns.Msg) *dns.Msg {
|
||||
m := new(dns.Msg)
|
||||
m.SetRcode(req, dns.RcodeNameError)
|
||||
m.Ns = []dns.RR{s.NewSOA()}
|
||||
m.Ns[0].Header().Ttl = s.config.MinTtl
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *server) ServerFailure(req *dns.Msg) *dns.Msg {
|
||||
m := new(dns.Msg)
|
||||
m.SetRcode(req, dns.RcodeServerFailure)
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *server) RoundRobin(rrs []dns.RR) {
|
||||
if !s.config.RoundRobin {
|
||||
return
|
||||
}
|
||||
// If we have more than 1 CNAME don't touch the packet, because some stub resolver (=glibc)
|
||||
// can't deal with the returned packet if the CNAMEs need to be accesses in the reverse order.
|
||||
cname := 0
|
||||
for _, r := range rrs {
|
||||
if r.Header().Rrtype == dns.TypeCNAME {
|
||||
cname++
|
||||
if cname > 1 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch l := len(rrs); l {
|
||||
case 2:
|
||||
if dns.Id()%2 == 0 {
|
||||
rrs[0], rrs[1] = rrs[1], rrs[0]
|
||||
}
|
||||
default:
|
||||
for j := 0; j < l*(int(dns.Id())%4+1); j++ {
|
||||
q := int(dns.Id()) % l
|
||||
p := int(dns.Id()) % l
|
||||
if q == p {
|
||||
p = (p + 1) % l
|
||||
}
|
||||
rrs[q], rrs[p] = rrs[p], rrs[q]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// dedup will de-duplicate a message on a per section basis.
|
||||
// Multiple identical (same name, class, type and rdata) RRs will be coalesced into one.
|
||||
func (s *server) dedup(m *dns.Msg) *dns.Msg {
|
||||
// Answer section
|
||||
ma := make(map[string]dns.RR)
|
||||
for _, a := range m.Answer {
|
||||
// Or use Pack()... Think this function also could be placed in go dns.
|
||||
s1 := a.Header().Name
|
||||
s1 += strconv.Itoa(int(a.Header().Class))
|
||||
s1 += strconv.Itoa(int(a.Header().Rrtype))
|
||||
// there can only be one CNAME for an ownername
|
||||
if a.Header().Rrtype == dns.TypeCNAME {
|
||||
if _, ok := ma[s1]; ok {
|
||||
// already exist, randomly overwrite if roundrobin is true
|
||||
// Note: even with roundrobin *off* this depends on the
|
||||
// order we get the names.
|
||||
if s.config.RoundRobin && dns.Id()%2 == 0 {
|
||||
ma[s1] = a
|
||||
continue
|
||||
}
|
||||
}
|
||||
ma[s1] = a
|
||||
continue
|
||||
}
|
||||
for i := 1; i <= dns.NumField(a); i++ {
|
||||
s1 += dns.Field(a, i)
|
||||
}
|
||||
ma[s1] = a
|
||||
}
|
||||
// Only is our map is smaller than the #RR in the answer section we should reset the RRs
|
||||
// in the section it self
|
||||
if len(ma) < len(m.Answer) {
|
||||
i := 0
|
||||
for _, v := range ma {
|
||||
m.Answer[i] = v
|
||||
i++
|
||||
}
|
||||
m.Answer = m.Answer[:len(ma)]
|
||||
}
|
||||
|
||||
// Additional section
|
||||
me := make(map[string]dns.RR)
|
||||
for _, e := range m.Extra {
|
||||
s1 := e.Header().Name
|
||||
s1 += strconv.Itoa(int(e.Header().Class))
|
||||
s1 += strconv.Itoa(int(e.Header().Rrtype))
|
||||
// there can only be one CNAME for an ownername
|
||||
if e.Header().Rrtype == dns.TypeCNAME {
|
||||
if _, ok := me[s1]; ok {
|
||||
// already exist, randomly overwrite if roundrobin is true
|
||||
if s.config.RoundRobin && dns.Id()%2 == 0 {
|
||||
me[s1] = e
|
||||
continue
|
||||
}
|
||||
}
|
||||
me[s1] = e
|
||||
continue
|
||||
}
|
||||
for i := 1; i <= dns.NumField(e); i++ {
|
||||
s1 += dns.Field(e, i)
|
||||
}
|
||||
me[s1] = e
|
||||
}
|
||||
|
||||
if len(me) < len(m.Extra) {
|
||||
i := 0
|
||||
for _, v := range me {
|
||||
m.Extra[i] = v
|
||||
i++
|
||||
}
|
||||
m.Extra = m.Extra[:len(me)]
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// overflowOrTruncated writes back an error to the client if the message does not fit.
|
||||
// It updates prometheus metrics. If something has been written to the client, true
|
||||
// will be returned.
|
||||
func (s *server) overflowOrTruncated(w dns.ResponseWriter, m *dns.Msg, bufsize int, sy metrics.System) bool {
|
||||
switch isTCP(w) {
|
||||
case true:
|
||||
if _, overflow := Fit(m, dns.MaxMsgSize, true); overflow {
|
||||
metrics.ReportErrorCount(m, sy)
|
||||
msgFail := s.ServerFailure(m)
|
||||
w.WriteMsg(msgFail)
|
||||
return true
|
||||
}
|
||||
case false:
|
||||
// Overflow with udp always results in TC.
|
||||
Fit(m, bufsize, false)
|
||||
metrics.ReportErrorCount(m, sy)
|
||||
if m.Truncated {
|
||||
w.WriteMsg(m)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isTCP returns true if the client is connecting over TCP.
|
||||
func isTCP(w dns.ResponseWriter) bool {
|
||||
_, ok := w.RemoteAddr().(*net.TCPAddr)
|
||||
return ok
|
||||
}
|
||||
|
||||
// etcNameError return a NameError to the client if the error
|
||||
// returned from etcd has ErrorCode == 100.
|
||||
func isEtcdNameError(err error, s *server) bool {
|
||||
if e, ok := err.(etcd.Error); ok && e.Code == etcd.ErrorCodeKeyNotFound {
|
||||
return true
|
||||
}
|
||||
if err != nil {
|
||||
logf("error from backend: %s", err)
|
||||
}
|
||||
return false
|
||||
}
|
124
vendor/github.com/skynetservices/skydns/server/stub.go
generated
vendored
124
vendor/github.com/skynetservices/skydns/server/stub.go
generated
vendored
@ -1,124 +0,0 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/skynetservices/skydns/msg"
|
||||
)
|
||||
|
||||
const ednsStubCode = dns.EDNS0LOCALSTART + 10
|
||||
|
||||
// ednsStub is the EDNS0 record we add to stub queries. Queries which have this record are
|
||||
// not forwarded again.
|
||||
var ednsStub = func() *dns.OPT {
|
||||
o := new(dns.OPT)
|
||||
o.Hdr.Name = "."
|
||||
o.Hdr.Rrtype = dns.TypeOPT
|
||||
e := new(dns.EDNS0_LOCAL)
|
||||
e.Code = ednsStubCode
|
||||
e.Data = []byte{1}
|
||||
o.Option = append(o.Option, e)
|
||||
return o
|
||||
}()
|
||||
|
||||
// Look in .../dns/stub/<domain>/xx for msg.Services. Loop through them
|
||||
// extract <domain> and add them as forwarders (ip:port-combos) for
|
||||
// the stub zones. Only numeric (i.e. IP address) hosts are used.
|
||||
func (s *server) UpdateStubZones() {
|
||||
stubmap := make(map[string][]string)
|
||||
|
||||
services, err := s.backend.Records("stub.dns."+s.config.Domain, false)
|
||||
if err != nil {
|
||||
logf("stub zone update failed: %s", err)
|
||||
return
|
||||
}
|
||||
for _, serv := range services {
|
||||
if serv.Port == 0 {
|
||||
serv.Port = 53
|
||||
}
|
||||
ip := net.ParseIP(serv.Host)
|
||||
if ip == nil {
|
||||
logf("stub zone non-address %s seen for: %s", serv.Key, serv.Host)
|
||||
continue
|
||||
}
|
||||
|
||||
domain := msg.Domain(serv.Key)
|
||||
// Chop of left most label, because that is used as the nameserver place holder
|
||||
// and drop the right most labels that belong to localDomain.
|
||||
labels := dns.SplitDomainName(domain)
|
||||
domain = dns.Fqdn(strings.Join(labels[1:len(labels)-dns.CountLabel(s.config.localDomain)], "."))
|
||||
|
||||
// If the remaining name equals s.config.LocalDomain we ignore it.
|
||||
if domain == s.config.localDomain {
|
||||
logf("not adding stub zone for my own domain")
|
||||
continue
|
||||
}
|
||||
stubmap[domain] = append(stubmap[domain], net.JoinHostPort(serv.Host, strconv.Itoa(serv.Port)))
|
||||
}
|
||||
|
||||
s.config.stub = &stubmap
|
||||
}
|
||||
|
||||
// ServeDNSStubForward forwards a request to a nameservers and returns the response.
|
||||
func (s *server) ServeDNSStubForward(w dns.ResponseWriter, req *dns.Msg, ns []string) *dns.Msg {
|
||||
// Check EDNS0 Stub option, if set drop the packet.
|
||||
option := req.IsEdns0()
|
||||
if option != nil {
|
||||
for _, o := range option.Option {
|
||||
if o.Option() == ednsStubCode && len(o.(*dns.EDNS0_LOCAL).Data) == 1 &&
|
||||
o.(*dns.EDNS0_LOCAL).Data[0] == 1 {
|
||||
// Maybe log source IP here?
|
||||
logf("not fowarding stub request to another stub")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a custom EDNS0 option to the packet, so we can detect loops
|
||||
// when 2 stubs are forwarding to each other.
|
||||
if option != nil {
|
||||
option.Option = append(option.Option, &dns.EDNS0_LOCAL{ednsStubCode, []byte{1}})
|
||||
} else {
|
||||
req.Extra = append(req.Extra, ednsStub)
|
||||
}
|
||||
|
||||
var (
|
||||
r *dns.Msg
|
||||
err error
|
||||
)
|
||||
|
||||
// Use request Id for "random" nameserver selection.
|
||||
nsid := int(req.Id) % len(ns)
|
||||
try := 0
|
||||
Redo:
|
||||
if isTCP(w) {
|
||||
r, err = exchangeWithRetry(s.dnsTCPclient, req, ns[nsid])
|
||||
} else {
|
||||
r, err = exchangeWithRetry(s.dnsUDPclient, req, ns[nsid])
|
||||
}
|
||||
if err == nil {
|
||||
r.Compress = true
|
||||
r.Id = req.Id
|
||||
w.WriteMsg(r)
|
||||
return r
|
||||
}
|
||||
// Seen an error, this can only mean, "server not reached", try again
|
||||
// but only if we have not exausted our nameservers.
|
||||
if try < len(ns) {
|
||||
try++
|
||||
nsid = (nsid + 1) % len(ns)
|
||||
goto Redo
|
||||
}
|
||||
|
||||
logf("failure to forward stub request %q", err)
|
||||
m := s.ServerFailure(req)
|
||||
w.WriteMsg(m)
|
||||
return m
|
||||
}
|
64
vendor/github.com/skynetservices/skydns/singleflight/singleflight.go
generated
vendored
64
vendor/github.com/skynetservices/skydns/singleflight/singleflight.go
generated
vendored
@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright 2012 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package singleflight provides a duplicate function call suppression
|
||||
// mechanism.
|
||||
package singleflight
|
||||
|
||||
import "sync"
|
||||
|
||||
// call is an in-flight or completed Do call
|
||||
type call struct {
|
||||
wg sync.WaitGroup
|
||||
val interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
// Group represents a class of work and forms a namespace in which
|
||||
// units of work can be executed with duplicate suppression.
|
||||
type Group struct {
|
||||
mu sync.Mutex // protects m
|
||||
m map[string]*call // lazily initialized
|
||||
}
|
||||
|
||||
// Do executes and returns the results of the given function, making
|
||||
// sure that only one execution is in-flight for a given key at a
|
||||
// time. If a duplicate comes in, the duplicate caller waits for the
|
||||
// original to complete and receives the same results.
|
||||
func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
|
||||
g.mu.Lock()
|
||||
if g.m == nil {
|
||||
g.m = make(map[string]*call)
|
||||
}
|
||||
if c, ok := g.m[key]; ok {
|
||||
g.mu.Unlock()
|
||||
c.wg.Wait()
|
||||
return c.val, c.err
|
||||
}
|
||||
c := new(call)
|
||||
c.wg.Add(1)
|
||||
g.m[key] = c
|
||||
g.mu.Unlock()
|
||||
|
||||
c.val, c.err = fn()
|
||||
c.wg.Done()
|
||||
|
||||
g.mu.Lock()
|
||||
delete(g.m, key)
|
||||
g.mu.Unlock()
|
||||
|
||||
return c.val, c.err
|
||||
}
|
Loading…
Reference in New Issue
Block a user