Merge pull request #23930 from ArtfulCoder/vendor-skydns
Automatic merge from submit-queue Use SkyDNS as a library for a more integrated kube DNS
This commit is contained in:
53
Godeps/.license_file_state
generated
53
Godeps/.license_file_state
generated
@@ -71,6 +71,10 @@ raw.githubusercontent.com/dgrijalva/jwt-go/master/NOTICE
|
|||||||
raw.githubusercontent.com/dgrijalva/jwt-go/master/NOTICE.txt
|
raw.githubusercontent.com/dgrijalva/jwt-go/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/dgrijalva/jwt-go/master/README
|
raw.githubusercontent.com/dgrijalva/jwt-go/master/README
|
||||||
raw.githubusercontent.com/dgrijalva/jwt-go/master/README.md
|
raw.githubusercontent.com/dgrijalva/jwt-go/master/README.md
|
||||||
|
raw.githubusercontent.com/docker/distribution/master/NOTICE
|
||||||
|
raw.githubusercontent.com/docker/distribution/master/NOTICE.txt
|
||||||
|
raw.githubusercontent.com/docker/distribution/master/README
|
||||||
|
raw.githubusercontent.com/docker/distribution/master/README.md
|
||||||
raw.githubusercontent.com/docker/engine-api/master/NOTICE
|
raw.githubusercontent.com/docker/engine-api/master/NOTICE
|
||||||
raw.githubusercontent.com/docker/engine-api/master/NOTICE.txt
|
raw.githubusercontent.com/docker/engine-api/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/docker/engine-api/master/README
|
raw.githubusercontent.com/docker/engine-api/master/README
|
||||||
@@ -129,6 +133,10 @@ raw.githubusercontent.com/golang/groupcache/master/NOTICE
|
|||||||
raw.githubusercontent.com/golang/groupcache/master/NOTICE.txt
|
raw.githubusercontent.com/golang/groupcache/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/golang/groupcache/master/README
|
raw.githubusercontent.com/golang/groupcache/master/README
|
||||||
raw.githubusercontent.com/golang/groupcache/master/README.md
|
raw.githubusercontent.com/golang/groupcache/master/README.md
|
||||||
|
raw.githubusercontent.com/golang/mock/master/NOTICE
|
||||||
|
raw.githubusercontent.com/golang/mock/master/NOTICE.txt
|
||||||
|
raw.githubusercontent.com/golang/mock/master/README
|
||||||
|
raw.githubusercontent.com/golang/mock/master/README.md
|
||||||
raw.githubusercontent.com/golang/protobuf/master/NOTICE
|
raw.githubusercontent.com/golang/protobuf/master/NOTICE
|
||||||
raw.githubusercontent.com/golang/protobuf/master/NOTICE.txt
|
raw.githubusercontent.com/golang/protobuf/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/golang/protobuf/master/README
|
raw.githubusercontent.com/golang/protobuf/master/README
|
||||||
@@ -247,7 +255,6 @@ raw.githubusercontent.com/pmezard/go-difflib/master/NOTICE
|
|||||||
raw.githubusercontent.com/pmezard/go-difflib/master/NOTICE.txt
|
raw.githubusercontent.com/pmezard/go-difflib/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/pmezard/go-difflib/master/README
|
raw.githubusercontent.com/pmezard/go-difflib/master/README
|
||||||
raw.githubusercontent.com/pmezard/go-difflib/master/README.md
|
raw.githubusercontent.com/pmezard/go-difflib/master/README.md
|
||||||
raw.githubusercontent.com/prometheus/common/master/LICENSE
|
|
||||||
raw.githubusercontent.com/prometheus/common/master/LICENSE.code
|
raw.githubusercontent.com/prometheus/common/master/LICENSE.code
|
||||||
raw.githubusercontent.com/prometheus/common/master/LICENSE.txt
|
raw.githubusercontent.com/prometheus/common/master/LICENSE.txt
|
||||||
raw.githubusercontent.com/prometheus/common/master/LICENSE.md
|
raw.githubusercontent.com/prometheus/common/master/LICENSE.md
|
||||||
@@ -315,6 +322,10 @@ raw.githubusercontent.com/vishvananda/netlink/master/NOTICE
|
|||||||
raw.githubusercontent.com/vishvananda/netlink/master/NOTICE.txt
|
raw.githubusercontent.com/vishvananda/netlink/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/vishvananda/netlink/master/README
|
raw.githubusercontent.com/vishvananda/netlink/master/README
|
||||||
raw.githubusercontent.com/vishvananda/netlink/master/README.md
|
raw.githubusercontent.com/vishvananda/netlink/master/README.md
|
||||||
|
raw.githubusercontent.com/vmware/govmomi/master/NOTICE
|
||||||
|
raw.githubusercontent.com/vmware/govmomi/master/NOTICE.txt
|
||||||
|
raw.githubusercontent.com/vmware/govmomi/master/README
|
||||||
|
raw.githubusercontent.com/vmware/govmomi/master/README.md
|
||||||
raw.githubusercontent.com/xiang90/probing/master/NOTICE
|
raw.githubusercontent.com/xiang90/probing/master/NOTICE
|
||||||
raw.githubusercontent.com/xiang90/probing/master/NOTICE.txt
|
raw.githubusercontent.com/xiang90/probing/master/NOTICE.txt
|
||||||
raw.githubusercontent.com/xiang90/probing/master/README
|
raw.githubusercontent.com/xiang90/probing/master/README
|
||||||
@@ -367,6 +378,10 @@ gopkg.in/gcfg.v1/master/NOTICE
|
|||||||
gopkg.in/gcfg.v1/master/NOTICE.txt
|
gopkg.in/gcfg.v1/master/NOTICE.txt
|
||||||
gopkg.in/gcfg.v1/master/README
|
gopkg.in/gcfg.v1/master/README
|
||||||
gopkg.in/gcfg.v1/master/README.md
|
gopkg.in/gcfg.v1/master/README.md
|
||||||
|
gopkg.in/inf.v0/master/NOTICE
|
||||||
|
gopkg.in/inf.v0/master/NOTICE.txt
|
||||||
|
gopkg.in/inf.v0/master/README
|
||||||
|
gopkg.in/inf.v0/master/README.md
|
||||||
gopkg.in/natefinch/master/NOTICE
|
gopkg.in/natefinch/master/NOTICE
|
||||||
gopkg.in/natefinch/master/NOTICE.txt
|
gopkg.in/natefinch/master/NOTICE.txt
|
||||||
gopkg.in/natefinch/master/README
|
gopkg.in/natefinch/master/README
|
||||||
@@ -379,39 +394,3 @@ k8s.io/heapster/master/NOTICE
|
|||||||
k8s.io/heapster/master/NOTICE.txt
|
k8s.io/heapster/master/NOTICE.txt
|
||||||
k8s.io/heapster/master/README
|
k8s.io/heapster/master/README
|
||||||
k8s.io/heapster/master/README.md
|
k8s.io/heapster/master/README.md
|
||||||
speter.net/go/master/NOTICE
|
|
||||||
speter.net/go/master/NOTICE.txt
|
|
||||||
speter.net/go/master/README
|
|
||||||
speter.net/go/master/README.md
|
|
||||||
gopkg.in/gcfg.v1/master/NOTICE
|
|
||||||
gopkg.in/gcfg.v1/master/NOTICE.txt
|
|
||||||
gopkg.in/gcfg.v1/master/README
|
|
||||||
gopkg.in/gcfg.v1/master/README.md
|
|
||||||
raw.githubusercontent.com/docker/engine-api/master/NOTICE
|
|
||||||
raw.githubusercontent.com/docker/engine-api/master/NOTICE.txt
|
|
||||||
raw.githubusercontent.com/docker/engine-api/master/README
|
|
||||||
raw.githubusercontent.com/docker/engine-api/master/README.md
|
|
||||||
raw.githubusercontent.com/docker/go-connections/master/NOTICE
|
|
||||||
raw.githubusercontent.com/docker/go-connections/master/NOTICE.txt
|
|
||||||
raw.githubusercontent.com/docker/go-connections/master/README
|
|
||||||
raw.githubusercontent.com/docker/go-connections/master/README.md
|
|
||||||
raw.githubusercontent.com/Microsoft/go-winio/master/NOTICE
|
|
||||||
raw.githubusercontent.com/Microsoft/go-winio/master/NOTICE.txt
|
|
||||||
raw.githubusercontent.com/Microsoft/go-winio/master/README
|
|
||||||
raw.githubusercontent.com/Microsoft/go-winio/master/README.md
|
|
||||||
raw.githubusercontent.com/docker/distribution/master/NOTICE
|
|
||||||
raw.githubusercontent.com/docker/distribution/master/NOTICE.txt
|
|
||||||
raw.githubusercontent.com/docker/distribution/master/README
|
|
||||||
raw.githubusercontent.com/docker/distribution/master/README.md
|
|
||||||
raw.githubusercontent.com/golang/mock/master/NOTICE
|
|
||||||
raw.githubusercontent.com/golang/mock/master/NOTICE.txt
|
|
||||||
raw.githubusercontent.com/golang/mock/master/README
|
|
||||||
raw.githubusercontent.com/golang/mock/master/README.md
|
|
||||||
raw.githubusercontent.com/vmware/govmomi/master/NOTICE
|
|
||||||
raw.githubusercontent.com/vmware/govmomi/master/NOTICE.txt
|
|
||||||
raw.githubusercontent.com/vmware/govmomi/master/README
|
|
||||||
raw.githubusercontent.com/vmware/govmomi/master/README.md
|
|
||||||
gopkg.in/inf.v0/master/NOTICE
|
|
||||||
gopkg.in/inf.v0/master/NOTICE.txt
|
|
||||||
gopkg.in/inf.v0/master/README
|
|
||||||
gopkg.in/inf.v0/master/README.md
|
|
||||||
|
|||||||
31
Godeps/Godeps.json
generated
31
Godeps/Godeps.json
generated
@@ -507,6 +507,11 @@
|
|||||||
"ImportPath": "github.com/coreos/go-semver/semver",
|
"ImportPath": "github.com/coreos/go-semver/semver",
|
||||||
"Rev": "d043ae190b3202550d026daf009359bb5d761672"
|
"Rev": "d043ae190b3202550d026daf009359bb5d761672"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/coreos/go-systemd/activation",
|
||||||
|
"Comment": "v4",
|
||||||
|
"Rev": "b4a58d95188dd092ae20072bac14cece0e67c388"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/coreos/go-systemd/daemon",
|
"ImportPath": "github.com/coreos/go-systemd/daemon",
|
||||||
"Comment": "v4",
|
"Comment": "v4",
|
||||||
@@ -1335,7 +1340,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/miekg/dns",
|
"ImportPath": "github.com/miekg/dns",
|
||||||
"Rev": "3f504e8dabd5d562e997d19ce0200aa41973e1b2"
|
"Rev": "c2b278e70f35902fd68b54b69238cd10bb1b7451"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mistifyio/go-zfs",
|
"ImportPath": "github.com/mistifyio/go-zfs",
|
||||||
@@ -1781,10 +1786,30 @@
|
|||||||
"ImportPath": "github.com/shurcooL/sanitized_anchor_name",
|
"ImportPath": "github.com/shurcooL/sanitized_anchor_name",
|
||||||
"Rev": "9a8b7d4e8f347bfa230879db9d7d4e4d9e19f962"
|
"Rev": "9a8b7d4e8f347bfa230879db9d7d4e4d9e19f962"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/skynetservices/skydns/cache",
|
||||||
|
"Comment": "2.5.3a-32-gf7b6fb7",
|
||||||
|
"Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/skynetservices/skydns/metrics",
|
||||||
|
"Comment": "2.5.3a-32-gf7b6fb7",
|
||||||
|
"Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/skynetservices/skydns/msg",
|
"ImportPath": "github.com/skynetservices/skydns/msg",
|
||||||
"Comment": "2.5.1a",
|
"Comment": "2.5.3a-32-gf7b6fb7",
|
||||||
"Rev": "1be70b5b8aa07acccd972146d84011b670af88b4"
|
"Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/skynetservices/skydns/server",
|
||||||
|
"Comment": "2.5.3a-32-gf7b6fb7",
|
||||||
|
"Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/skynetservices/skydns/singleflight",
|
||||||
|
"Comment": "2.5.3a-32-gf7b6fb7",
|
||||||
|
"Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/spf13/cobra",
|
"ImportPath": "github.com/spf13/cobra",
|
||||||
|
|||||||
704
Godeps/LICENSES
generated
704
Godeps/LICENSES
generated
@@ -19925,6 +19925,202 @@ This product includes software developed at CoreOS, Inc.
|
|||||||
limitations under the License.
|
limitations under the 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/daemon licensed under: =
|
= vendor/github.com/coreos/go-systemd/daemon licensed under: =
|
||||||
|
|
||||||
@@ -53806,6 +54002,208 @@ SoundCloud Ltd. (http://soundcloud.com/).
|
|||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/prometheus/common/expfmt licensed under: =
|
= vendor/github.com/prometheus/common/expfmt 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:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) 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
|
||||||
|
|
||||||
|
(d) 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.
|
||||||
|
|
||||||
Copyright 2015 The Prometheus Authors
|
Copyright 2015 The Prometheus Authors
|
||||||
|
|
||||||
This product includes software developed at
|
This product includes software developed at
|
||||||
@@ -53814,6 +54212,208 @@ SoundCloud Ltd. (http://soundcloud.com/).
|
|||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/prometheus/common/model licensed under: =
|
= vendor/github.com/prometheus/common/model 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:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) 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
|
||||||
|
|
||||||
|
(d) 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.
|
||||||
|
|
||||||
Copyright 2015 The Prometheus Authors
|
Copyright 2015 The Prometheus Authors
|
||||||
|
|
||||||
This product includes software developed at
|
This product includes software developed at
|
||||||
@@ -59292,6 +59892,58 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
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/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/msg licensed under: =
|
= vendor/github.com/skynetservices/skydns/msg licensed under: =
|
||||||
|
|
||||||
@@ -59318,6 +59970,58 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= 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/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/spf13/cobra licensed under: =
|
= vendor/github.com/spf13/cobra licensed under: =
|
||||||
|
|
||||||
|
|||||||
18
build/kube-dns/Dockerfile
Normal file
18
build/kube-dns/Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
FROM BASEIMAGE
|
||||||
|
MAINTAINER Tim Hockin <thockin@google.com>
|
||||||
|
ADD kube-dns /
|
||||||
|
ENTRYPOINT ["/kube-dns"]
|
||||||
66
build/kube-dns/Makefile
Normal file
66
build/kube-dns/Makefile
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# Makefile for the Docker image gcr.io/google_containers/kube2sky
|
||||||
|
# MAINTAINER: Tim Hockin <thockin@google.com>
|
||||||
|
# If you update this image please bump the tag value before pushing.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# [ARCH=amd64] [TAG=1.0] [REGISTRY=gcr.io/google_containers] [BASEIMAGE=busybox] make container
|
||||||
|
|
||||||
|
# Default registry, arch and tag. This can be overwritten by arguments to make
|
||||||
|
PLATFORM?=linux
|
||||||
|
ARCH?=amd64
|
||||||
|
TAG?=1.0
|
||||||
|
REGISTRY?=gcr.io/google_containers
|
||||||
|
|
||||||
|
GOLANG_VERSION=1.6
|
||||||
|
GOARM=6
|
||||||
|
KUBE_ROOT=$(shell pwd)/../..
|
||||||
|
TEMP_DIR:=$(shell mktemp -d)
|
||||||
|
|
||||||
|
ifeq ($(ARCH),amd64)
|
||||||
|
BASEIMAGE?=busybox
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),arm)
|
||||||
|
BASEIMAGE?=armel/busybox
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),arm64)
|
||||||
|
BASEIMAGE?=aarch64/busybox
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),ppc64le)
|
||||||
|
BASEIMAGE?=ppc64le/busybox
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
all: container
|
||||||
|
|
||||||
|
container:
|
||||||
|
# Copy the content in this dir to the temp dir
|
||||||
|
cp $(KUBE_ROOT)/_output/local/bin/$(PLATFORM)/$(ARCH)/kube-dns $(TEMP_DIR)
|
||||||
|
cp $(KUBE_ROOT)/build/kube-dns/Dockerfile $(TEMP_DIR)
|
||||||
|
|
||||||
|
# Replace BASEIMAGE with the real base image
|
||||||
|
cd $(TEMP_DIR) && sed -i "s|BASEIMAGE|$(BASEIMAGE)|g" Dockerfile
|
||||||
|
|
||||||
|
# And build the image
|
||||||
|
docker build -t $(REGISTRY)/kubedns-$(ARCH):$(TAG) $(TEMP_DIR)
|
||||||
|
|
||||||
|
# delete temp dir
|
||||||
|
rm -rf $(TEMP_DIR)
|
||||||
|
|
||||||
|
push: container
|
||||||
|
gcloud docker push $(REGISTRY)/kubedns-$(ARCH):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: all container push
|
||||||
@@ -73,17 +73,17 @@ addon-dir-create:
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if pillar.get('enable_cluster_dns', '').lower() == 'true' %}
|
{% if pillar.get('enable_cluster_dns', '').lower() == 'true' %}
|
||||||
/etc/kubernetes/addons/dns/skydns-svc.yaml:
|
/etc/kubernetes/addons/dns/kubedns-svc.yaml:
|
||||||
file.managed:
|
file.managed:
|
||||||
- source: salt://kube-addons/dns/skydns-svc.yaml.in
|
- source: salt://kube-dns/kubedns-svc.yaml.in
|
||||||
- template: jinja
|
- template: jinja
|
||||||
- group: root
|
- group: root
|
||||||
- dir_mode: 755
|
- dir_mode: 755
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|
||||||
/etc/kubernetes/addons/dns/skydns-rc.yaml:
|
/etc/kubernetes/addons/dns/kubedns-rc.yaml:
|
||||||
file.managed:
|
file.managed:
|
||||||
- source: salt://kube-addons/dns/skydns-rc.yaml.in
|
- source: salt://kube-dns/kubedns-rc.yaml.in
|
||||||
- template: jinja
|
- template: jinja
|
||||||
- group: root
|
- group: root
|
||||||
- dir_mode: 755
|
- dir_mode: 755
|
||||||
|
|||||||
80
cluster/saltbase/salt/kube-dns/kubedns-rc.yaml.in
Normal file
80
cluster/saltbase/salt/kube-dns/kubedns-rc.yaml.in
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ReplicationController
|
||||||
|
metadata:
|
||||||
|
name: kube-dns-v12
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
k8s-app: kube-dns
|
||||||
|
version: v12
|
||||||
|
kubernetes.io/cluster-service: "true"
|
||||||
|
spec:
|
||||||
|
replicas: {{ pillar['dns_replicas'] }}
|
||||||
|
selector:
|
||||||
|
k8s-app: kube-dns
|
||||||
|
version: v12
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: kube-dns
|
||||||
|
version: v12
|
||||||
|
kubernetes.io/cluster-service: "true"
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: kubedns
|
||||||
|
image: gcr.io/google_containers/kubedns-amd64:1.0
|
||||||
|
resources:
|
||||||
|
# TODO: Set memory limits when we've profiled the container for large
|
||||||
|
# clusters, then set request = limit to keep this container in
|
||||||
|
# guaranteed class. Currently, this container falls into the
|
||||||
|
# "burstable" category so the kubelet doesn't backoff from restarting it.
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 200Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 50Mi
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8080
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
timeoutSeconds: 5
|
||||||
|
successThreshold: 1
|
||||||
|
failureThreshold: 5
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /readiness
|
||||||
|
port: 8081
|
||||||
|
scheme: HTTP
|
||||||
|
# we poll on pod startup for the Kubernetes master service and
|
||||||
|
# only setup the /readiness HTTP server once that's available.
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
args:
|
||||||
|
# command = "/kube-dns"
|
||||||
|
- --domain={{ pillar['dns_domain'] }}.
|
||||||
|
ports:
|
||||||
|
- containerPort: 53
|
||||||
|
name: dns
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 53
|
||||||
|
name: dns-tcp
|
||||||
|
protocol: TCP
|
||||||
|
- name: healthz
|
||||||
|
image: gcr.io/google_containers/exechealthz:1.0
|
||||||
|
resources:
|
||||||
|
# keep request = limit to keep this container in guaranteed class
|
||||||
|
limits:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 20Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 20Mi
|
||||||
|
args:
|
||||||
|
- -cmd=nslookup kubernetes.default.svc.{{ pillar['dns_domain'] }} 127.0.0.1 >/dev/null
|
||||||
|
- -port=8080
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
dnsPolicy: Default # Don't use cluster DNS.
|
||||||
20
cluster/saltbase/salt/kube-dns/kubedns-svc.yaml.in
Normal file
20
cluster/saltbase/salt/kube-dns/kubedns-svc.yaml.in
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: kube-dns
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
k8s-app: kube-dns
|
||||||
|
kubernetes.io/cluster-service: "true"
|
||||||
|
kubernetes.io/name: "KubeDNS"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
k8s-app: kube-dns
|
||||||
|
clusterIP: {{ pillar['dns_server'] }}
|
||||||
|
ports:
|
||||||
|
- name: dns
|
||||||
|
port: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
port: 53
|
||||||
|
protocol: TCP
|
||||||
103
cmd/kube-dns/app/options/options.go
Normal file
103
cmd/kube-dns/app/options/options.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 options contains flags for initializing a proxy.
|
||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"k8s.io/kubernetes/pkg/util/validation"
|
||||||
|
_ "net/http/pprof"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KubeDNSConfig struct {
|
||||||
|
ClusterDomain string
|
||||||
|
KubeConfigFile string
|
||||||
|
KubeMasterURL string
|
||||||
|
HealthzPort int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKubeDNSConfig() *KubeDNSConfig {
|
||||||
|
return &KubeDNSConfig{
|
||||||
|
ClusterDomain: "cluster.local.",
|
||||||
|
KubeConfigFile: "",
|
||||||
|
KubeMasterURL: "",
|
||||||
|
HealthzPort: 8081,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type clusterDomainVar struct {
|
||||||
|
val *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m clusterDomainVar) Set(v string) error {
|
||||||
|
v = strings.TrimSuffix(v, ".")
|
||||||
|
segments := strings.Split(v, ".")
|
||||||
|
for _, segment := range segments {
|
||||||
|
if errs := validation.IsDNS1123Label(segment); len(errs) > 0 {
|
||||||
|
return fmt.Errorf("Not a valid DNS label. %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(v, ".") {
|
||||||
|
v = fmt.Sprintf("%s.", v)
|
||||||
|
}
|
||||||
|
*m.val = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m clusterDomainVar) String() string {
|
||||||
|
return *m.val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m clusterDomainVar) Type() string {
|
||||||
|
return "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
type kubeMasterURLVar struct {
|
||||||
|
val *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m kubeMasterURLVar) Set(v string) error {
|
||||||
|
parsedURL, err := url.Parse(os.ExpandEnv(v))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse kube-master-url")
|
||||||
|
}
|
||||||
|
if parsedURL.Scheme == "" || parsedURL.Host == "" || parsedURL.Host == ":" {
|
||||||
|
return fmt.Errorf("invalid kube-master-url specified")
|
||||||
|
}
|
||||||
|
*m.val = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m kubeMasterURLVar) String() string {
|
||||||
|
return *m.val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m kubeMasterURLVar) Type() string {
|
||||||
|
return "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *KubeDNSConfig) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
fs.Var(clusterDomainVar{&s.ClusterDomain}, "domain", "domain under which to create names")
|
||||||
|
fs.StringVar(&s.KubeConfigFile, "kubecfg-file", s.KubeConfigFile, "Location of kubecfg file for access to kubernetes master service; --kube-master-url overrides the URL part of this; if neither this nor --kube-master-url are provided, defaults to service account tokens")
|
||||||
|
fs.Var(kubeMasterURLVar{&s.KubeMasterURL}, "kube-master-url", "URL to reach kubernetes master. Env variables in this flag will be expanded.")
|
||||||
|
fs.IntVar(&s.HealthzPort, "healthz-port", s.HealthzPort, "port on which to serve a kube-dns HTTP readiness probe.")
|
||||||
|
}
|
||||||
136
cmd/kube-dns/app/server.go
Normal file
136
cmd/kube-dns/app/server.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/skynetservices/skydns/metrics"
|
||||||
|
"github.com/skynetservices/skydns/server"
|
||||||
|
"k8s.io/kubernetes/cmd/kube-dns/app/options"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
|
kclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
kclientcmd "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
|
kdns "k8s.io/kubernetes/pkg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KubeDNSServer struct {
|
||||||
|
// DNS domain name.
|
||||||
|
domain string
|
||||||
|
healthzPort int
|
||||||
|
kd *kdns.KubeDNS
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKubeDNSServerDefault(config *options.KubeDNSConfig) *KubeDNSServer {
|
||||||
|
ks := KubeDNSServer{
|
||||||
|
domain: config.ClusterDomain,
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeClient, err := newKubeClient(config)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed to create a kubernetes client: %v", err)
|
||||||
|
}
|
||||||
|
ks.healthzPort = config.HealthzPort
|
||||||
|
ks.kd = kdns.NewKubeDNS(kubeClient, config.ClusterDomain)
|
||||||
|
return &ks
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: evaluate using pkg/client/clientcmd
|
||||||
|
func newKubeClient(dnsConfig *options.KubeDNSConfig) (*kclient.Client, error) {
|
||||||
|
var (
|
||||||
|
config *restclient.Config
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if dnsConfig.KubeMasterURL != "" && dnsConfig.KubeConfigFile == "" {
|
||||||
|
// Only --kube-master-url was provided.
|
||||||
|
config = &restclient.Config{
|
||||||
|
Host: dnsConfig.KubeMasterURL,
|
||||||
|
ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We either have:
|
||||||
|
// 1) --kube-master-url and --kubecfg-file
|
||||||
|
// 2) just --kubecfg-file
|
||||||
|
// 3) neither flag
|
||||||
|
// In any case, the logic is the same. If (3), this will automatically
|
||||||
|
// fall back on the service account token.
|
||||||
|
overrides := &kclientcmd.ConfigOverrides{}
|
||||||
|
overrides.ClusterInfo.Server = dnsConfig.KubeMasterURL // might be "", but that is OK
|
||||||
|
rules := &kclientcmd.ClientConfigLoadingRules{ExplicitPath: dnsConfig.KubeConfigFile} // might be "", but that is OK
|
||||||
|
if config, err = kclientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Infof("Using %s for kubernetes master", config.Host)
|
||||||
|
glog.Infof("Using kubernetes API %v", config.GroupVersion)
|
||||||
|
return kclient.New(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *KubeDNSServer) Run() {
|
||||||
|
setupSignalHandlers()
|
||||||
|
server.startSkyDNSServer()
|
||||||
|
server.kd.Start()
|
||||||
|
server.setupHealthzHandlers()
|
||||||
|
glog.Infof("Setting up Healthz Handler(/readiness, /cache) on port :%d", server.healthzPort)
|
||||||
|
glog.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", server.healthzPort), nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupHealthzHandlers sets up a readiness and liveness endpoint for kube2sky.
|
||||||
|
func (server *KubeDNSServer) setupHealthzHandlers() {
|
||||||
|
http.HandleFunc("/readiness", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
fmt.Fprintf(w, "ok\n")
|
||||||
|
})
|
||||||
|
http.HandleFunc("/cache", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
serializedJSON, err := server.kd.GetCacheAsJSON()
|
||||||
|
if err == nil {
|
||||||
|
fmt.Fprint(w, serializedJSON)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
fmt.Fprint(w, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupSignalHandlers runs a goroutine that waits on SIGINT or SIGTERM and logs it
|
||||||
|
// before exiting.
|
||||||
|
func setupSignalHandlers() {
|
||||||
|
sigChan := make(chan os.Signal)
|
||||||
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
glog.Fatalf("Received signal: %s", <-sigChan)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *KubeDNSServer) startSkyDNSServer() {
|
||||||
|
skydnsConfig := &server.Config{Domain: d.domain, DnsAddr: "0.0.0.0:53"}
|
||||||
|
server.SetDefaults(skydnsConfig)
|
||||||
|
s := server.New(d.kd, skydnsConfig)
|
||||||
|
if err := metrics.Metrics(); err != nil {
|
||||||
|
glog.Fatalf("skydns: %s", err)
|
||||||
|
} else {
|
||||||
|
glog.Infof("skydns: metrics enabled on :%s%s", metrics.Port, metrics.Path)
|
||||||
|
}
|
||||||
|
go s.Run()
|
||||||
|
}
|
||||||
39
cmd/kube-dns/dns.go
Normal file
39
cmd/kube-dns/dns.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"k8s.io/kubernetes/cmd/kube-dns/app"
|
||||||
|
"k8s.io/kubernetes/cmd/kube-dns/app/options"
|
||||||
|
"k8s.io/kubernetes/pkg/util"
|
||||||
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
|
"k8s.io/kubernetes/pkg/version/verflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
config := options.NewKubeDNSConfig()
|
||||||
|
config.AddFlags(pflag.CommandLine)
|
||||||
|
|
||||||
|
flag.InitFlags()
|
||||||
|
util.InitLogs()
|
||||||
|
defer util.FlushLogs()
|
||||||
|
|
||||||
|
verflag.PrintAndExitIfRequested()
|
||||||
|
server := app.NewKubeDNSServerDefault(config)
|
||||||
|
server.Run()
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ fi
|
|||||||
# kube::build::source_targets in build/common.sh as well.
|
# kube::build::source_targets in build/common.sh as well.
|
||||||
kube::golang::server_targets() {
|
kube::golang::server_targets() {
|
||||||
local targets=(
|
local targets=(
|
||||||
|
cmd/kube-dns
|
||||||
cmd/kube-proxy
|
cmd/kube-proxy
|
||||||
cmd/kube-apiserver
|
cmd/kube-apiserver
|
||||||
cmd/kube-controller-manager
|
cmd/kube-controller-manager
|
||||||
@@ -159,6 +160,7 @@ readonly KUBE_ALL_BINARIES=("${KUBE_ALL_TARGETS[@]##*/}")
|
|||||||
readonly KUBE_STATIC_LIBRARIES=(
|
readonly KUBE_STATIC_LIBRARIES=(
|
||||||
kube-apiserver
|
kube-apiserver
|
||||||
kube-controller-manager
|
kube-controller-manager
|
||||||
|
kube-dns
|
||||||
kube-scheduler
|
kube-scheduler
|
||||||
kube-proxy
|
kube-proxy
|
||||||
kubectl
|
kubectl
|
||||||
|
|||||||
455
pkg/dns/dns.go
Normal file
455
pkg/dns/dns.go
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
etcd "github.com/coreos/etcd/client"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
skymsg "github.com/skynetservices/skydns/msg"
|
||||||
|
kapi "k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/endpoints"
|
||||||
|
kcache "k8s.io/kubernetes/pkg/client/cache"
|
||||||
|
kclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
kframework "k8s.io/kubernetes/pkg/controller/framework"
|
||||||
|
kselector "k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/util/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
kubernetesSvcName = "kubernetes"
|
||||||
|
|
||||||
|
// A subdomain added to the user specified domain for all services.
|
||||||
|
serviceSubdomain = "svc"
|
||||||
|
|
||||||
|
// A subdomain added to the user specified dmoain for all pods.
|
||||||
|
podSubdomain = "pod"
|
||||||
|
|
||||||
|
// Resync period for the kube controller loop.
|
||||||
|
resyncPeriod = 5 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
type KubeDNS struct {
|
||||||
|
// kubeClient makes calls to API Server and registers calls with API Server
|
||||||
|
// to get Endpoints and Service objects.
|
||||||
|
kubeClient *kclient.Client
|
||||||
|
|
||||||
|
// The domain for which this DNS Server is authoritative.
|
||||||
|
domain string
|
||||||
|
|
||||||
|
// A cache that contains all the endpoints in the system.
|
||||||
|
endpointsStore kcache.Store
|
||||||
|
|
||||||
|
// A cache that contains all the services in the system.
|
||||||
|
servicesStore kcache.Store
|
||||||
|
|
||||||
|
// stores DNS records for the domain.
|
||||||
|
// A Records and SRV Records for (regular) services and headless Services.
|
||||||
|
cache *TreeCache
|
||||||
|
|
||||||
|
// caller is responsible for using the cacheLock before invoking methods on cache
|
||||||
|
// the cache is not thread-safe, and the caller can guarantee thread safety by using
|
||||||
|
// the cacheLock
|
||||||
|
cacheLock sync.RWMutex
|
||||||
|
|
||||||
|
// The domain for which this DNS Server is authoritative, in array format and reversed.
|
||||||
|
// e.g. if domain is "cluster.local", domainPath is []string{"local", "cluster"}
|
||||||
|
domainPath []string
|
||||||
|
|
||||||
|
// endpointsController invokes registered callbacks when endpoints change.
|
||||||
|
endpointsController *kframework.Controller
|
||||||
|
|
||||||
|
// serviceController invokes registered callbacks when services change.
|
||||||
|
serviceController *kframework.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKubeDNS(client *kclient.Client, domain string) *KubeDNS {
|
||||||
|
kd := &KubeDNS{
|
||||||
|
kubeClient: client,
|
||||||
|
domain: domain,
|
||||||
|
cache: NewTreeCache(),
|
||||||
|
cacheLock: sync.RWMutex{},
|
||||||
|
domainPath: reverseArray(strings.Split(strings.TrimRight(domain, "."), ".")),
|
||||||
|
}
|
||||||
|
kd.setEndpointsStore()
|
||||||
|
kd.setServicesStore()
|
||||||
|
return kd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) Start() {
|
||||||
|
go kd.endpointsController.Run(wait.NeverStop)
|
||||||
|
go kd.serviceController.Run(wait.NeverStop)
|
||||||
|
// Wait synchronously for the Kubernetes service and add a DNS record for it.
|
||||||
|
// This ensures that the Start function returns only after having received Service objects
|
||||||
|
// from APIServer.
|
||||||
|
// TODO: we might not have to wait for kubernetes service specifically. We should just wait
|
||||||
|
// for a list operation to be complete from APIServer.
|
||||||
|
kd.waitForKubernetesService()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) waitForKubernetesService() (svc *kapi.Service) {
|
||||||
|
name := fmt.Sprintf("%v/%v", kapi.NamespaceDefault, kubernetesSvcName)
|
||||||
|
glog.Infof("Waiting for service: %v", name)
|
||||||
|
var err error
|
||||||
|
servicePollInterval := 1 * time.Second
|
||||||
|
for {
|
||||||
|
svc, err = kd.kubeClient.Services(kapi.NamespaceDefault).Get(kubernetesSvcName)
|
||||||
|
if err != nil || svc == nil {
|
||||||
|
glog.Infof("Ignoring error while waiting for service %v: %v. Sleeping %v before retrying.", name, err, servicePollInterval)
|
||||||
|
time.Sleep(servicePollInterval)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) GetCacheAsJSON() (string, error) {
|
||||||
|
kd.cacheLock.RLock()
|
||||||
|
defer kd.cacheLock.RUnlock()
|
||||||
|
json, err := kd.cache.Serialize()
|
||||||
|
return json, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) setServicesStore() {
|
||||||
|
// Returns a cache.ListWatch that gets all changes to services.
|
||||||
|
serviceWatch := kcache.NewListWatchFromClient(kd.kubeClient, "services", kapi.NamespaceAll, kselector.Everything())
|
||||||
|
kd.servicesStore, kd.serviceController = kframework.NewInformer(
|
||||||
|
serviceWatch,
|
||||||
|
&kapi.Service{},
|
||||||
|
resyncPeriod,
|
||||||
|
kframework.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: kd.newService,
|
||||||
|
DeleteFunc: kd.removeService,
|
||||||
|
UpdateFunc: kd.updateService,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) setEndpointsStore() {
|
||||||
|
// Returns a cache.ListWatch that gets all changes to endpoints.
|
||||||
|
endpointsWatch := kcache.NewListWatchFromClient(kd.kubeClient, "endpoints", kapi.NamespaceAll, kselector.Everything())
|
||||||
|
kd.endpointsStore, kd.endpointsController = kframework.NewInformer(
|
||||||
|
endpointsWatch,
|
||||||
|
&kapi.Endpoints{},
|
||||||
|
resyncPeriod,
|
||||||
|
kframework.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: kd.handleEndpointAdd,
|
||||||
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||||
|
// TODO: Avoid unwanted updates.
|
||||||
|
kd.handleEndpointAdd(newObj)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertIsService(obj interface{}) (*kapi.Service, bool) {
|
||||||
|
if service, ok := obj.(*kapi.Service); ok {
|
||||||
|
return service, ok
|
||||||
|
} else {
|
||||||
|
glog.Errorf("Type assertion failed! Expected 'Service', got %T", service)
|
||||||
|
return nil, ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) newService(obj interface{}) {
|
||||||
|
if service, ok := assertIsService(obj); ok {
|
||||||
|
// if ClusterIP is not set, a DNS entry should not be created
|
||||||
|
if !kapi.IsServiceIPSet(service) {
|
||||||
|
kd.newHeadlessService(service)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(service.Spec.Ports) == 0 {
|
||||||
|
glog.Warning("Unexpected service with no ports, this should not have happend: %v", service)
|
||||||
|
}
|
||||||
|
kd.newPortalService(service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) removeService(obj interface{}) {
|
||||||
|
if s, ok := assertIsService(obj); ok {
|
||||||
|
subCachePath := append(kd.domainPath, serviceSubdomain, s.Namespace, s.Name)
|
||||||
|
kd.cacheLock.Lock()
|
||||||
|
defer kd.cacheLock.Unlock()
|
||||||
|
kd.cache.deletePath(subCachePath...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) updateService(oldObj, newObj interface{}) {
|
||||||
|
kd.newService(newObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) handleEndpointAdd(obj interface{}) {
|
||||||
|
if e, ok := obj.(*kapi.Endpoints); ok {
|
||||||
|
kd.addDNSUsingEndpoints(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) addDNSUsingEndpoints(e *kapi.Endpoints) error {
|
||||||
|
svc, err := kd.getServiceFromEndpoints(e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if svc == nil || kapi.IsServiceIPSet(svc) {
|
||||||
|
// No headless service found corresponding to endpoints object.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return kd.generateRecordsForHeadlessService(e, svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) getServiceFromEndpoints(e *kapi.Endpoints) (*kapi.Service, error) {
|
||||||
|
key, err := kcache.MetaNamespaceKeyFunc(e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
obj, exists, err := kd.servicesStore.GetByKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get service object from services store - %v", err)
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
glog.V(1).Infof("could not find service for endpoint %q in namespace %q", e.Name, e.Namespace)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if svc, ok := assertIsService(obj); ok {
|
||||||
|
return svc, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("got a non service object in services store %v", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) newPortalService(service *kapi.Service) {
|
||||||
|
subCache := NewTreeCache()
|
||||||
|
recordValue, recordLabel := getSkyMsg(service.Spec.ClusterIP, 0)
|
||||||
|
subCache.setEntry(recordLabel, recordValue)
|
||||||
|
|
||||||
|
// Generate SRV Records
|
||||||
|
for i := range service.Spec.Ports {
|
||||||
|
port := &service.Spec.Ports[i]
|
||||||
|
if port.Name != "" && port.Protocol != "" {
|
||||||
|
srvValue := kd.generateSRVRecordValue(service, int(port.Port))
|
||||||
|
subCache.setEntry(recordLabel, srvValue, "_"+strings.ToLower(string(port.Protocol)), "_"+port.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subCachePath := append(kd.domainPath, serviceSubdomain, service.Namespace)
|
||||||
|
kd.cacheLock.Lock()
|
||||||
|
defer kd.cacheLock.Unlock()
|
||||||
|
kd.cache.setSubCache(service.Name, subCache, subCachePath...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) generateRecordsForHeadlessService(e *kapi.Endpoints, svc *kapi.Service) error {
|
||||||
|
// TODO: remove this after v1.4 is released and the old annotations are EOL
|
||||||
|
podHostnames, err := getPodHostnamesFromAnnotation(e.Annotations)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
subCache := NewTreeCache()
|
||||||
|
glog.V(4).Infof("Endpoints Annotations: %v", e.Annotations)
|
||||||
|
for idx := range e.Subsets {
|
||||||
|
for subIdx := range e.Subsets[idx].Addresses {
|
||||||
|
address := &e.Subsets[idx].Addresses[subIdx]
|
||||||
|
endpointIP := address.IP
|
||||||
|
recordValue, endpointName := getSkyMsg(endpointIP, 0)
|
||||||
|
if hostLabel, exists := getHostname(address, podHostnames); exists {
|
||||||
|
endpointName = hostLabel
|
||||||
|
}
|
||||||
|
subCache.setEntry(endpointName, recordValue)
|
||||||
|
for portIdx := range e.Subsets[idx].Ports {
|
||||||
|
endpointPort := &e.Subsets[idx].Ports[portIdx]
|
||||||
|
if endpointPort.Name != "" && endpointPort.Protocol != "" {
|
||||||
|
srvValue := kd.generateSRVRecordValue(svc, int(endpointPort.Port), endpointName)
|
||||||
|
subCache.setEntry(endpointName, srvValue, "_"+strings.ToLower(string(endpointPort.Protocol)), "_"+endpointPort.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subCachePath := append(kd.domainPath, serviceSubdomain, svc.Namespace)
|
||||||
|
kd.cacheLock.Lock()
|
||||||
|
defer kd.cacheLock.Unlock()
|
||||||
|
kd.cache.setSubCache(svc.Name, subCache, subCachePath...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHostname(address *kapi.EndpointAddress, podHostnames map[string]endpoints.HostRecord) (string, bool) {
|
||||||
|
if len(address.Hostname) > 0 {
|
||||||
|
return address.Hostname, true
|
||||||
|
}
|
||||||
|
if hostRecord, exists := podHostnames[address.IP]; exists && len(validation.IsDNS1123Label(hostRecord.HostName)) == 0 {
|
||||||
|
return hostRecord.HostName, true
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPodHostnamesFromAnnotation(annotations map[string]string) (map[string]endpoints.HostRecord, error) {
|
||||||
|
hostnames := map[string]endpoints.HostRecord{}
|
||||||
|
|
||||||
|
if annotations != nil {
|
||||||
|
if serializedHostnames, exists := annotations[endpoints.PodHostnamesAnnotation]; exists && len(serializedHostnames) > 0 {
|
||||||
|
err := json.Unmarshal([]byte(serializedHostnames), &hostnames)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hostnames, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) generateSRVRecordValue(svc *kapi.Service, portNumber int, labels ...string) *skymsg.Service {
|
||||||
|
host := strings.Join([]string{svc.Name, svc.Namespace, serviceSubdomain, kd.domain}, ".")
|
||||||
|
for _, cNameLabel := range labels {
|
||||||
|
host = cNameLabel + "." + host
|
||||||
|
}
|
||||||
|
recordValue, _ := getSkyMsg(host, portNumber)
|
||||||
|
return recordValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates skydns records for a headless service.
|
||||||
|
func (kd *KubeDNS) newHeadlessService(service *kapi.Service) error {
|
||||||
|
// Create an A record for every pod in the service.
|
||||||
|
// This record must be periodically updated.
|
||||||
|
// Format is as follows:
|
||||||
|
// For a service x, with pods a and b create DNS records,
|
||||||
|
// a.x.ns.domain. and, b.x.ns.domain.
|
||||||
|
key, err := kcache.MetaNamespaceKeyFunc(service)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e, exists, err := kd.endpointsStore.GetByKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get endpoints object from endpoints store - %v", err)
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
glog.V(1).Infof("Could not find endpoints for service %q in namespace %q. DNS records will be created once endpoints show up.", service.Name, service.Namespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if e, ok := e.(*kapi.Endpoints); ok {
|
||||||
|
return kd.generateRecordsForHeadlessService(e, service)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) Records(name string, exact bool) ([]skymsg.Service, error) {
|
||||||
|
glog.Infof("Received DNS Request:%s, exact:%v", name, exact)
|
||||||
|
trimmed := strings.TrimRight(name, ".")
|
||||||
|
segments := strings.Split(trimmed, ".")
|
||||||
|
path := reverseArray(segments)
|
||||||
|
if kd.isPodRecord(path) {
|
||||||
|
ip, err := kd.getPodIP(path)
|
||||||
|
if err == nil {
|
||||||
|
skyMsg, _ := getSkyMsg(ip, 0)
|
||||||
|
return []skymsg.Service{*skyMsg}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if exact {
|
||||||
|
key := path[len(path)-1]
|
||||||
|
if key == "" {
|
||||||
|
return []skymsg.Service{}, nil
|
||||||
|
}
|
||||||
|
kd.cacheLock.RLock()
|
||||||
|
defer kd.cacheLock.RUnlock()
|
||||||
|
if record, ok := kd.cache.getEntry(key, path[:len(path)-1]...); ok {
|
||||||
|
return []skymsg.Service{*(record.(*skymsg.Service))}, nil
|
||||||
|
}
|
||||||
|
return nil, etcd.Error{Code: etcd.ErrorCodeKeyNotFound}
|
||||||
|
}
|
||||||
|
|
||||||
|
kd.cacheLock.RLock()
|
||||||
|
defer kd.cacheLock.RUnlock()
|
||||||
|
records := kd.cache.getValuesForPathWithWildcards(path...)
|
||||||
|
retval := []skymsg.Service{}
|
||||||
|
for _, val := range records {
|
||||||
|
retval = append(retval, *(val.(*skymsg.Service)))
|
||||||
|
}
|
||||||
|
glog.Infof("records:%v, retval:%v, path:%v", records, retval, path)
|
||||||
|
if len(retval) == 0 {
|
||||||
|
return nil, etcd.Error{Code: etcd.ErrorCodeKeyNotFound}
|
||||||
|
}
|
||||||
|
return retval, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) ReverseRecord(name string) (*skymsg.Service, error) {
|
||||||
|
glog.Infof("Received ReverseRecord Request:%s", name)
|
||||||
|
|
||||||
|
segments := strings.Split(strings.TrimRight(name, "."), ".")
|
||||||
|
|
||||||
|
for _, k := range segments {
|
||||||
|
if k == "*" {
|
||||||
|
return nil, fmt.Errorf("reverse can not contain wildcards")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("must be exactly one service record")
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g {"local", "cluster", "pod", "default", "10-0-0-1"}
|
||||||
|
func (kd *KubeDNS) isPodRecord(path []string) bool {
|
||||||
|
if len(path) != len(kd.domainPath)+3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if path[len(kd.domainPath)] != "pod" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, segment := range path {
|
||||||
|
if segment == "*" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kd *KubeDNS) getPodIP(path []string) (string, error) {
|
||||||
|
ipStr := path[len(path)-1]
|
||||||
|
ip := strings.Replace(ipStr, "-", ".", -1)
|
||||||
|
if parsed := net.ParseIP(ip); parsed != nil {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("Invalid IP Address %v", ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns record in a format that SkyDNS understands.
|
||||||
|
// Also return the hash of the record.
|
||||||
|
func getSkyMsg(ip string, port int) (*skymsg.Service, string) {
|
||||||
|
msg := &skymsg.Service{
|
||||||
|
Host: ip,
|
||||||
|
Port: port,
|
||||||
|
Priority: 10,
|
||||||
|
Weight: 10,
|
||||||
|
Ttl: 30,
|
||||||
|
}
|
||||||
|
s := fmt.Sprintf("%v", msg)
|
||||||
|
h := fnv.New32a()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
hash := fmt.Sprintf("%x", h.Sum32())
|
||||||
|
glog.Infof("DNS Record:%s, hash:%s", s, hash)
|
||||||
|
return msg, fmt.Sprintf("%x", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reverseArray(arr []string) []string {
|
||||||
|
for i := 0; i < len(arr)/2; i++ {
|
||||||
|
j := len(arr) - i - 1
|
||||||
|
arr[i], arr[j] = arr[j], arr[i]
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
381
pkg/dns/dns_test.go
Normal file
381
pkg/dns/dns_test.go
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
skymsg "github.com/skynetservices/skydns/msg"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
kapi "k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testDomain = "cluster.local."
|
||||||
|
testService = "testservice"
|
||||||
|
testNamespace = "default"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newKubeDNS() *KubeDNS {
|
||||||
|
kd := &KubeDNS{
|
||||||
|
domain: testDomain,
|
||||||
|
endpointsStore: cache.NewStore(cache.MetaNamespaceKeyFunc),
|
||||||
|
servicesStore: cache.NewStore(cache.MetaNamespaceKeyFunc),
|
||||||
|
cache: NewTreeCache(),
|
||||||
|
cacheLock: sync.RWMutex{},
|
||||||
|
domainPath: reverseArray(strings.Split(strings.TrimRight(testDomain, "."), ".")),
|
||||||
|
}
|
||||||
|
return kd
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPodDns(t *testing.T) {
|
||||||
|
const (
|
||||||
|
testPodIP = "1.2.3.4"
|
||||||
|
sanitizedPodIP = "1-2-3-4"
|
||||||
|
)
|
||||||
|
kd := newKubeDNS()
|
||||||
|
|
||||||
|
records, err := kd.Records(sanitizedPodIP+".default.pod."+kd.domain, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(records))
|
||||||
|
assert.Equal(t, testPodIP, records[0].Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnnamedSinglePortService(t *testing.T) {
|
||||||
|
kd := newKubeDNS()
|
||||||
|
s := newService(testNamespace, testService, "1.2.3.4", "", 80)
|
||||||
|
// Add the service
|
||||||
|
kd.newService(s)
|
||||||
|
assertDNSForClusterIP(t, kd, s)
|
||||||
|
// Delete the service
|
||||||
|
kd.removeService(s)
|
||||||
|
assertNoDNSForClusterIP(t, kd, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedSinglePortService(t *testing.T) {
|
||||||
|
const (
|
||||||
|
portName1 = "http1"
|
||||||
|
portName2 = "http2"
|
||||||
|
)
|
||||||
|
kd := newKubeDNS()
|
||||||
|
s := newService(testNamespace, testService, "1.2.3.4", portName1, 80)
|
||||||
|
// Add the service
|
||||||
|
kd.newService(s)
|
||||||
|
assertDNSForClusterIP(t, kd, s)
|
||||||
|
assertSRVForNamedPort(t, kd, s, portName1)
|
||||||
|
|
||||||
|
newService := *s
|
||||||
|
// update the portName of the service
|
||||||
|
newService.Spec.Ports[0].Name = portName2
|
||||||
|
kd.updateService(s, &newService)
|
||||||
|
assertDNSForClusterIP(t, kd, s)
|
||||||
|
assertSRVForNamedPort(t, kd, s, portName2)
|
||||||
|
assertNoSRVForNamedPort(t, kd, s, portName1)
|
||||||
|
|
||||||
|
// Delete the service
|
||||||
|
kd.removeService(s)
|
||||||
|
assertNoDNSForClusterIP(t, kd, s)
|
||||||
|
assertNoSRVForNamedPort(t, kd, s, portName1)
|
||||||
|
assertNoSRVForNamedPort(t, kd, s, portName2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeadlessService(t *testing.T) {
|
||||||
|
kd := newKubeDNS()
|
||||||
|
s := newHeadlessService()
|
||||||
|
assert.NoError(t, kd.servicesStore.Add(s))
|
||||||
|
endpoints := newEndpoints(s, newSubsetWithOnePort("", 80, "10.0.0.1", "10.0.0.2"), newSubsetWithOnePort("", 8080, "10.0.0.3", "10.0.0.4"))
|
||||||
|
|
||||||
|
assert.NoError(t, kd.endpointsStore.Add(endpoints))
|
||||||
|
kd.newService(s)
|
||||||
|
assertDNSForHeadlessService(t, kd, endpoints)
|
||||||
|
kd.removeService(s)
|
||||||
|
assertNoDNSForHeadlessService(t, kd, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeadlessServiceWithNamedPorts(t *testing.T) {
|
||||||
|
kd := newKubeDNS()
|
||||||
|
service := newHeadlessService()
|
||||||
|
// add service to store
|
||||||
|
assert.NoError(t, kd.servicesStore.Add(service))
|
||||||
|
endpoints := newEndpoints(service, newSubsetWithTwoPorts("http1", 80, "http2", 81, "10.0.0.1", "10.0.0.2"),
|
||||||
|
newSubsetWithOnePort("https", 443, "10.0.0.3", "10.0.0.4"))
|
||||||
|
|
||||||
|
// We expect 10 records. 6 SRV records. 4 POD records.
|
||||||
|
// add endpoints
|
||||||
|
assert.NoError(t, kd.endpointsStore.Add(endpoints))
|
||||||
|
|
||||||
|
// add service
|
||||||
|
kd.newService(service)
|
||||||
|
assertDNSForHeadlessService(t, kd, endpoints)
|
||||||
|
assertSRVForHeadlessService(t, kd, service, endpoints)
|
||||||
|
|
||||||
|
// reduce endpoints
|
||||||
|
endpoints.Subsets = endpoints.Subsets[:1]
|
||||||
|
kd.handleEndpointAdd(endpoints)
|
||||||
|
// We expect 6 records. 4 SRV records. 2 POD records.
|
||||||
|
assertDNSForHeadlessService(t, kd, endpoints)
|
||||||
|
assertSRVForHeadlessService(t, kd, service, endpoints)
|
||||||
|
|
||||||
|
kd.removeService(service)
|
||||||
|
assertNoDNSForHeadlessService(t, kd, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeadlessServiceEndpointsUpdate(t *testing.T) {
|
||||||
|
kd := newKubeDNS()
|
||||||
|
service := newHeadlessService()
|
||||||
|
// add service to store
|
||||||
|
assert.NoError(t, kd.servicesStore.Add(service))
|
||||||
|
|
||||||
|
endpoints := newEndpoints(service, newSubsetWithOnePort("", 80, "10.0.0.1", "10.0.0.2"))
|
||||||
|
// add endpoints to store
|
||||||
|
assert.NoError(t, kd.endpointsStore.Add(endpoints))
|
||||||
|
|
||||||
|
// add service
|
||||||
|
kd.newService(service)
|
||||||
|
assertDNSForHeadlessService(t, kd, endpoints)
|
||||||
|
|
||||||
|
// increase endpoints
|
||||||
|
endpoints.Subsets = append(endpoints.Subsets,
|
||||||
|
newSubsetWithOnePort("", 8080, "10.0.0.3", "10.0.0.4"),
|
||||||
|
)
|
||||||
|
// expected DNSRecords = 4
|
||||||
|
kd.handleEndpointAdd(endpoints)
|
||||||
|
assertDNSForHeadlessService(t, kd, endpoints)
|
||||||
|
|
||||||
|
// remove all endpoints
|
||||||
|
endpoints.Subsets = []kapi.EndpointSubset{}
|
||||||
|
kd.handleEndpointAdd(endpoints)
|
||||||
|
assertNoDNSForHeadlessService(t, kd, service)
|
||||||
|
|
||||||
|
// remove service
|
||||||
|
kd.removeService(service)
|
||||||
|
assertNoDNSForHeadlessService(t, kd, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeadlessServiceWithDelayedEndpointsAddition(t *testing.T) {
|
||||||
|
kd := newKubeDNS()
|
||||||
|
// create service
|
||||||
|
service := newHeadlessService()
|
||||||
|
|
||||||
|
// add service to store
|
||||||
|
assert.NoError(t, kd.servicesStore.Add(service))
|
||||||
|
|
||||||
|
// add service
|
||||||
|
kd.newService(service)
|
||||||
|
assertNoDNSForHeadlessService(t, kd, service)
|
||||||
|
|
||||||
|
// create endpoints
|
||||||
|
endpoints := newEndpoints(service, newSubsetWithOnePort("", 80, "10.0.0.1", "10.0.0.2"))
|
||||||
|
|
||||||
|
// add endpoints to store
|
||||||
|
assert.NoError(t, kd.endpointsStore.Add(endpoints))
|
||||||
|
|
||||||
|
// add endpoints
|
||||||
|
kd.handleEndpointAdd(endpoints)
|
||||||
|
|
||||||
|
assertDNSForHeadlessService(t, kd, endpoints)
|
||||||
|
|
||||||
|
// remove service
|
||||||
|
kd.removeService(service)
|
||||||
|
assertNoDNSForHeadlessService(t, kd, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newService(namespace, serviceName, clusterIP, portName string, portNumber int32) *kapi.Service {
|
||||||
|
service := kapi.Service{
|
||||||
|
ObjectMeta: kapi.ObjectMeta{
|
||||||
|
Name: serviceName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Spec: kapi.ServiceSpec{
|
||||||
|
ClusterIP: clusterIP,
|
||||||
|
Ports: []kapi.ServicePort{
|
||||||
|
{Port: portNumber, Name: portName, Protocol: "TCP"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &service
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHeadlessService() *kapi.Service {
|
||||||
|
service := kapi.Service{
|
||||||
|
ObjectMeta: kapi.ObjectMeta{
|
||||||
|
Name: testService,
|
||||||
|
Namespace: testNamespace,
|
||||||
|
},
|
||||||
|
Spec: kapi.ServiceSpec{
|
||||||
|
ClusterIP: "None",
|
||||||
|
Ports: []kapi.ServicePort{
|
||||||
|
{Port: 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &service
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEndpoints(service *kapi.Service, subsets ...kapi.EndpointSubset) *kapi.Endpoints {
|
||||||
|
endpoints := kapi.Endpoints{
|
||||||
|
ObjectMeta: service.ObjectMeta,
|
||||||
|
Subsets: []kapi.EndpointSubset{},
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints.Subsets = append(endpoints.Subsets, subsets...)
|
||||||
|
return &endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSubsetWithOnePort(portName string, port int32, ips ...string) kapi.EndpointSubset {
|
||||||
|
subset := newSubset()
|
||||||
|
subset.Ports = append(subset.Ports, kapi.EndpointPort{Port: port, Name: portName, Protocol: "TCP"})
|
||||||
|
for _, ip := range ips {
|
||||||
|
subset.Addresses = append(subset.Addresses, kapi.EndpointAddress{IP: ip})
|
||||||
|
}
|
||||||
|
return subset
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSubsetWithTwoPorts(portName1 string, portNumber1 int32, portName2 string, portNumber2 int32, ips ...string) kapi.EndpointSubset {
|
||||||
|
subset := newSubsetWithOnePort(portName1, portNumber1, ips...)
|
||||||
|
subset.Ports = append(subset.Ports, kapi.EndpointPort{Port: portNumber2, Name: portName2, Protocol: "TCP"})
|
||||||
|
return subset
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSubset() kapi.EndpointSubset {
|
||||||
|
subset := kapi.EndpointSubset{
|
||||||
|
Addresses: []kapi.EndpointAddress{},
|
||||||
|
Ports: []kapi.EndpointPort{},
|
||||||
|
}
|
||||||
|
return subset
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertSRVForHeadlessService(t *testing.T, kd *KubeDNS, s *kapi.Service, e *kapi.Endpoints) {
|
||||||
|
for _, subset := range e.Subsets {
|
||||||
|
for _, port := range subset.Ports {
|
||||||
|
records, err := kd.Records(getSRVFQDN(kd, s, port.Name), false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertRecordPortsMatchPort(t, port.Port, records)
|
||||||
|
assertCNameRecordsMatchEndpointIPs(t, kd, subset.Addresses, records)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertDNSForHeadlessService(t *testing.T, kd *KubeDNS, e *kapi.Endpoints) {
|
||||||
|
records, err := kd.Records(getEndpointsFQDN(kd, e), false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
endpoints := map[string]bool{}
|
||||||
|
for _, subset := range e.Subsets {
|
||||||
|
for _, endpointAddress := range subset.Addresses {
|
||||||
|
endpoints[endpointAddress.IP] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Equal(t, len(endpoints), len(records))
|
||||||
|
for _, record := range records {
|
||||||
|
_, found := endpoints[record.Host]
|
||||||
|
assert.True(t, found)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertRecordPortsMatchPort(t *testing.T, port int32, records []skymsg.Service) {
|
||||||
|
for _, record := range records {
|
||||||
|
assert.Equal(t, port, int32(record.Port))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertCNameRecordsMatchEndpointIPs(t *testing.T, kd *KubeDNS, e []kapi.EndpointAddress, records []skymsg.Service) {
|
||||||
|
endpoints := map[string]bool{}
|
||||||
|
for _, endpointAddress := range e {
|
||||||
|
endpoints[endpointAddress.IP] = true
|
||||||
|
}
|
||||||
|
assert.Equal(t, len(e), len(records), "unexpected record count")
|
||||||
|
for _, record := range records {
|
||||||
|
_, found := endpoints[getIPForCName(t, kd, record.Host)]
|
||||||
|
assert.True(t, found, "Did not find endpoint with address:%s", record.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIPForCName(t *testing.T, kd *KubeDNS, cname string) string {
|
||||||
|
records, err := kd.Records(cname, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(records), "Could not get IP for CNAME record for %s", cname)
|
||||||
|
assert.NotNil(t, net.ParseIP(records[0].Host), "Invalid IP address %q", records[0].Host)
|
||||||
|
return records[0].Host
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNoDNSForHeadlessService(t *testing.T, kd *KubeDNS, s *kapi.Service) {
|
||||||
|
records, err := kd.Records(getServiceFQDN(kd, s), false)
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Equal(t, 0, len(records))
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertSRVForNamedPort(t *testing.T, kd *KubeDNS, s *kapi.Service, portName string) {
|
||||||
|
records, err := kd.Records(getSRVFQDN(kd, s, portName), false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(records))
|
||||||
|
assert.Equal(t, getServiceFQDN(kd, s), records[0].Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNoSRVForNamedPort(t *testing.T, kd *KubeDNS, s *kapi.Service, portName string) {
|
||||||
|
records, err := kd.Records(getSRVFQDN(kd, s, portName), false)
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Equal(t, 0, len(records))
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNoDNSForClusterIP(t *testing.T, kd *KubeDNS, s *kapi.Service) {
|
||||||
|
serviceFQDN := getServiceFQDN(kd, s)
|
||||||
|
queries := getEquivalentQueries(serviceFQDN, s.Namespace)
|
||||||
|
for _, query := range queries {
|
||||||
|
records, err := kd.Records(query, false)
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Equal(t, 0, len(records))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertDNSForClusterIP(t *testing.T, kd *KubeDNS, s *kapi.Service) {
|
||||||
|
serviceFQDN := getServiceFQDN(kd, s)
|
||||||
|
queries := getEquivalentQueries(serviceFQDN, s.Namespace)
|
||||||
|
for _, query := range queries {
|
||||||
|
records, err := kd.Records(query, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(records))
|
||||||
|
assert.Equal(t, s.Spec.ClusterIP, records[0].Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEquivalentQueries(serviceFQDN, namespace string) []string {
|
||||||
|
return []string{
|
||||||
|
serviceFQDN,
|
||||||
|
strings.Replace(serviceFQDN, ".svc.", ".*.", 1),
|
||||||
|
strings.Replace(serviceFQDN, namespace, "*", 1),
|
||||||
|
strings.Replace(strings.Replace(serviceFQDN, namespace, "*", 1), ".svc.", ".*.", 1),
|
||||||
|
"*." + serviceFQDN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getServiceFQDN(kd *KubeDNS, s *kapi.Service) string {
|
||||||
|
return fmt.Sprintf("%s.%s.svc.%s", s.Name, s.Namespace, kd.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEndpointsFQDN(kd *KubeDNS, e *kapi.Endpoints) string {
|
||||||
|
return fmt.Sprintf("%s.%s.svc.%s", e.Name, e.Namespace, kd.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSRVFQDN(kd *KubeDNS, s *kapi.Service, portName string) string {
|
||||||
|
return fmt.Sprintf("_%s._tcp.%s.%s.svc.%s", portName, s.Name, s.Namespace, kd.domain)
|
||||||
|
}
|
||||||
247
pkg/dns/treecache.go
Normal file
247
pkg/dns/treecache.go
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TreeCache struct {
|
||||||
|
ChildNodes map[string]*TreeCache
|
||||||
|
Entries map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTreeCache() *TreeCache {
|
||||||
|
return &TreeCache{
|
||||||
|
ChildNodes: make(map[string]*TreeCache),
|
||||||
|
Entries: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) Serialize() (string, error) {
|
||||||
|
b, err := json.Marshal(cache)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var prettyJSON bytes.Buffer
|
||||||
|
err = json.Indent(&prettyJSON, b, "", "\t")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(prettyJSON.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) setEntry(key string, val interface{}, path ...string) {
|
||||||
|
node := cache.ensureChildNode(path...)
|
||||||
|
node.Entries[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) getSubCache(path ...string) *TreeCache {
|
||||||
|
childCache := cache
|
||||||
|
for _, subpath := range path {
|
||||||
|
childCache = childCache.ChildNodes[subpath]
|
||||||
|
if childCache == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return childCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) setSubCache(key string, subCache *TreeCache, path ...string) {
|
||||||
|
node := cache.ensureChildNode(path...)
|
||||||
|
node.ChildNodes[key] = subCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) getEntry(key string, path ...string) (interface{}, bool) {
|
||||||
|
childNode := cache.getSubCache(path...)
|
||||||
|
val, ok := childNode.Entries[key]
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) getValuesForPathWithWildcards(path ...string) []interface{} {
|
||||||
|
retval := []interface{}{}
|
||||||
|
nodesToExplore := []*TreeCache{cache}
|
||||||
|
for idx, subpath := range path {
|
||||||
|
nextNodesToExplore := []*TreeCache{}
|
||||||
|
if idx == len(path)-1 {
|
||||||
|
// if path ends on an entry, instead of a child node, add the entry
|
||||||
|
for _, node := range nodesToExplore {
|
||||||
|
if subpath == "*" {
|
||||||
|
nextNodesToExplore = append(nextNodesToExplore, node)
|
||||||
|
} else {
|
||||||
|
if val, ok := node.Entries[subpath]; ok {
|
||||||
|
retval = append(retval, val)
|
||||||
|
} else {
|
||||||
|
childNode := node.ChildNodes[subpath]
|
||||||
|
if childNode != nil {
|
||||||
|
nextNodesToExplore = append(nextNodesToExplore, childNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodesToExplore = nextNodesToExplore
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if subpath == "*" {
|
||||||
|
for _, node := range nodesToExplore {
|
||||||
|
for subkey, subnode := range node.ChildNodes {
|
||||||
|
if !strings.HasPrefix(subkey, "_") {
|
||||||
|
nextNodesToExplore = append(nextNodesToExplore, subnode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, node := range nodesToExplore {
|
||||||
|
childNode := node.ChildNodes[subpath]
|
||||||
|
if childNode != nil {
|
||||||
|
nextNodesToExplore = append(nextNodesToExplore, childNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodesToExplore = nextNodesToExplore
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, node := range nodesToExplore {
|
||||||
|
for _, val := range node.Entries {
|
||||||
|
retval = append(retval, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) deletePath(path ...string) bool {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if parentNode := cache.getSubCache(path[:len(path)-1]...); parentNode != nil {
|
||||||
|
if _, ok := parentNode.ChildNodes[path[len(path)-1]]; ok {
|
||||||
|
delete(parentNode.ChildNodes, path[len(path)-1])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) deleteEntry(key string, path ...string) bool {
|
||||||
|
childNode := cache.getSubCache(path...)
|
||||||
|
if childNode == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, ok := childNode.Entries[key]; ok {
|
||||||
|
delete(childNode.Entries, key)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) appendValues(recursive bool, ref [][]interface{}) {
|
||||||
|
for _, value := range cache.Entries {
|
||||||
|
ref[0] = append(ref[0], value)
|
||||||
|
}
|
||||||
|
if recursive {
|
||||||
|
for _, node := range cache.ChildNodes {
|
||||||
|
node.appendValues(recursive, ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cache *TreeCache) ensureChildNode(path ...string) *TreeCache {
|
||||||
|
childNode := cache
|
||||||
|
for _, subpath := range path {
|
||||||
|
newNode, ok := childNode.ChildNodes[subpath]
|
||||||
|
if !ok {
|
||||||
|
newNode = NewTreeCache()
|
||||||
|
childNode.ChildNodes[subpath] = newNode
|
||||||
|
}
|
||||||
|
childNode = newNode
|
||||||
|
}
|
||||||
|
return childNode
|
||||||
|
}
|
||||||
|
|
||||||
|
// unused function. keeping it around in commented-fashion
|
||||||
|
// in the future, we might need some form of this function so that
|
||||||
|
// we can serialize to a file in a mounted empty dir..
|
||||||
|
//const (
|
||||||
|
// dataFile = "data.dat"
|
||||||
|
// crcFile = "data.crc"
|
||||||
|
//)
|
||||||
|
//func (cache *TreeCache) Serialize(dir string) (string, error) {
|
||||||
|
// cache.m.RLock()
|
||||||
|
// defer cache.m.RUnlock()
|
||||||
|
// b, err := json.Marshal(cache)
|
||||||
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if err := ensureDir(dir, os.FileMode(0755)); err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// if err := ioutil.WriteFile(path.Join(dir, dataFile), b, 0644); err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// if err := ioutil.WriteFile(path.Join(dir, crcFile), getMD5(b), 0644); err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// return string(b), nil
|
||||||
|
//}
|
||||||
|
|
||||||
|
//func ensureDir(path string, perm os.FileMode) error {
|
||||||
|
// s, err := os.Stat(path)
|
||||||
|
// if err != nil || !s.IsDir() {
|
||||||
|
// return os.Mkdir(path, perm)
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
//}
|
||||||
|
|
||||||
|
//func getMD5(b []byte) []byte {
|
||||||
|
// h := md5.New()
|
||||||
|
// h.Write(b)
|
||||||
|
// return []byte(fmt.Sprintf("%x", h.Sum(nil)))
|
||||||
|
//}
|
||||||
|
|
||||||
|
// unused function. keeping it around in commented-fashion
|
||||||
|
// in the future, we might need some form of this function so that
|
||||||
|
// we can restart kube-dns, deserialize the tree and have a cache
|
||||||
|
// without having to wait for kube-dns to reach out to API server.
|
||||||
|
//func Deserialize(dir string) (*TreeCache, error) {
|
||||||
|
// b, err := ioutil.ReadFile(path.Join(dir, dataFile))
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// hash, err := ioutil.ReadFile(path.Join(dir, crcFile))
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// if !reflect.DeepEqual(hash, getMD5(b)) {
|
||||||
|
// return nil, fmt.Errorf("Checksum failed")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var cache TreeCache
|
||||||
|
// err = json.Unmarshal(b, &cache)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// cache.m = &sync.RWMutex{}
|
||||||
|
// return &cache, nil
|
||||||
|
//}
|
||||||
52
vendor/github.com/coreos/go-systemd/activation/files.go
generated
vendored
Normal file
52
vendor/github.com/coreos/go-systemd/activation/files.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// 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
Normal file
62
vendor/github.com/coreos/go-systemd/activation/listeners.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// 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
Normal file
37
vendor/github.com/coreos/go-systemd/activation/packetconns.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
22
vendor/github.com/miekg/dns/.travis.yml
generated
vendored
22
vendor/github.com/miekg/dns/.travis.yml
generated
vendored
@@ -1,21 +1,7 @@
|
|||||||
language: go
|
language: go
|
||||||
|
sudo: false
|
||||||
go:
|
go:
|
||||||
- 1.2
|
- 1.5
|
||||||
- 1.3
|
- 1.6
|
||||||
env:
|
|
||||||
# "gvm update" resets GOOS and GOARCH environment variable, workaround it by setting
|
|
||||||
# BUILD_GOOS and BUILD_GOARCH and overriding GOARCH and GOOS in the build script
|
|
||||||
global:
|
|
||||||
- BUILD_GOARCH=amd64
|
|
||||||
matrix:
|
|
||||||
- BUILD_GOOS=linux
|
|
||||||
- BUILD_GOOS=darwin
|
|
||||||
- BUILD_GOOS=windows
|
|
||||||
script:
|
script:
|
||||||
- gvm cross $BUILD_GOOS $BUILD_GOARCH
|
- go test -race -v -bench=.
|
||||||
- GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go build
|
|
||||||
|
|
||||||
# only test on linux
|
|
||||||
# also specify -short; the crypto tests fail in weird ways *sometimes*
|
|
||||||
# See issue #151
|
|
||||||
- if [ $BUILD_GOOS == "linux" ]; then GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go test -short -bench=.; fi
|
|
||||||
|
|||||||
43
vendor/github.com/miekg/dns/README.md
generated
vendored
43
vendor/github.com/miekg/dns/README.md
generated
vendored
@@ -10,9 +10,9 @@ If there is stuff you should know as a DNS programmer there isn't a convenience
|
|||||||
function for it. Server side and client side programming is supported, i.e. you
|
function for it. Server side and client side programming is supported, i.e. you
|
||||||
can build servers and resolvers with it.
|
can build servers and resolvers with it.
|
||||||
|
|
||||||
If you like this, you may also be interested in:
|
We try to keep the "master" branch as sane as possible and at the bleeding edge
|
||||||
|
of standards, avoiding breaking changes wherever reasonable. We support the last
|
||||||
* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver.
|
two versions of Go, currently: 1.4 and 1.5.
|
||||||
|
|
||||||
# Goals
|
# Goals
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ If you like this, you may also be interested in:
|
|||||||
|
|
||||||
A not-so-up-to-date-list-that-may-be-actually-current:
|
A not-so-up-to-date-list-that-may-be-actually-current:
|
||||||
|
|
||||||
|
* https://cloudflare.com
|
||||||
* https://github.com/abh/geodns
|
* https://github.com/abh/geodns
|
||||||
* http://www.statdns.com/
|
* http://www.statdns.com/
|
||||||
* http://www.dnsinspect.com/
|
* http://www.dnsinspect.com/
|
||||||
@@ -32,8 +33,21 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||||||
* https://github.com/fcambus/rrda
|
* https://github.com/fcambus/rrda
|
||||||
* https://github.com/kenshinx/godns
|
* https://github.com/kenshinx/godns
|
||||||
* https://github.com/skynetservices/skydns
|
* https://github.com/skynetservices/skydns
|
||||||
|
* https://github.com/hashicorp/consul
|
||||||
* https://github.com/DevelopersPL/godnsagent
|
* https://github.com/DevelopersPL/godnsagent
|
||||||
* https://github.com/duedil-ltd/discodns
|
* https://github.com/duedil-ltd/discodns
|
||||||
|
* https://github.com/StalkR/dns-reverse-proxy
|
||||||
|
* https://github.com/tianon/rawdns
|
||||||
|
* https://mesosphere.github.io/mesos-dns/
|
||||||
|
* https://pulse.turbobytes.com/
|
||||||
|
* https://play.google.com/store/apps/details?id=com.turbobytes.dig
|
||||||
|
* https://github.com/fcambus/statzone
|
||||||
|
* https://github.com/benschw/dns-clb-go
|
||||||
|
* https://github.com/corny/dnscheck for http://public-dns.info/
|
||||||
|
* https://namesmith.io
|
||||||
|
* https://github.com/miekg/unbound
|
||||||
|
* https://github.com/miekg/exdns
|
||||||
|
* https://dnslookup.org
|
||||||
|
|
||||||
Send pull request if you want to be listed here.
|
Send pull request if you want to be listed here.
|
||||||
|
|
||||||
@@ -50,6 +64,7 @@ Send pull request if you want to be listed here.
|
|||||||
* EDNS0, NSID;
|
* EDNS0, NSID;
|
||||||
* AXFR/IXFR;
|
* AXFR/IXFR;
|
||||||
* TSIG, SIG(0);
|
* TSIG, SIG(0);
|
||||||
|
* DNS over TLS: optional encrypted connection between client and server;
|
||||||
* DNS name compression;
|
* DNS name compression;
|
||||||
* Depends only on the standard library.
|
* Depends only on the standard library.
|
||||||
|
|
||||||
@@ -67,7 +82,7 @@ correctly, the following should work:
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
A short "how to use the API" is at the beginning of dns.go (this also will show
|
A short "how to use the API" is at the beginning of doc.go (this also will show
|
||||||
when you call `godoc github.com/miekg/dns`).
|
when you call `godoc github.com/miekg/dns`).
|
||||||
|
|
||||||
Example programs can be found in the `github.com/miekg/exdns` repository.
|
Example programs can be found in the `github.com/miekg/exdns` repository.
|
||||||
@@ -77,7 +92,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||||||
*all of them*
|
*all of them*
|
||||||
|
|
||||||
* 103{4,5} - DNS standard
|
* 103{4,5} - DNS standard
|
||||||
* 1348 - NSAP record
|
* 1348 - NSAP record (removed the record)
|
||||||
* 1982 - Serial Arithmetic
|
* 1982 - Serial Arithmetic
|
||||||
* 1876 - LOC record
|
* 1876 - LOC record
|
||||||
* 1995 - IXFR
|
* 1995 - IXFR
|
||||||
@@ -95,7 +110,8 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||||||
* 3225 - DO bit (DNSSEC OK)
|
* 3225 - DO bit (DNSSEC OK)
|
||||||
* 340{1,2,3} - NAPTR record
|
* 340{1,2,3} - NAPTR record
|
||||||
* 3445 - Limiting the scope of (DNS)KEY
|
* 3445 - Limiting the scope of (DNS)KEY
|
||||||
* 3597 - Unkown RRs
|
* 3597 - Unknown RRs
|
||||||
|
* 4025 - IPSECKEY
|
||||||
* 403{3,4,5} - DNSSEC + validation functions
|
* 403{3,4,5} - DNSSEC + validation functions
|
||||||
* 4255 - SSHFP record
|
* 4255 - SSHFP record
|
||||||
* 4343 - Case insensitivity
|
* 4343 - Case insensitivity
|
||||||
@@ -114,13 +130,16 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||||||
* 6605 - ECDSA
|
* 6605 - ECDSA
|
||||||
* 6725 - IANA Registry Update
|
* 6725 - IANA Registry Update
|
||||||
* 6742 - ILNP DNS
|
* 6742 - ILNP DNS
|
||||||
|
* 6840 - Clarifications and Implementation Notes for DNS Security
|
||||||
|
* 6844 - CAA record
|
||||||
* 6891 - EDNS0 update
|
* 6891 - EDNS0 update
|
||||||
* 6895 - DNS IANA considerations
|
* 6895 - DNS IANA considerations
|
||||||
* 6975 - Algorithm Understanding in DNSSEC
|
* 6975 - Algorithm Understanding in DNSSEC
|
||||||
* 7043 - EUI48/EUI64 records
|
* 7043 - EUI48/EUI64 records
|
||||||
* 7314 - DNS (EDNS) EXPIRE Option
|
* 7314 - DNS (EDNS) EXPIRE Option
|
||||||
* xxxx - URI record (draft)
|
* 7553 - URI record
|
||||||
* xxxx - EDNS0 DNS Update Lease (draft)
|
* xxxx - EDNS0 DNS Update Lease (draft)
|
||||||
|
* yyyy - DNS over TLS: Initiation and Performance Considerations (draft)
|
||||||
|
|
||||||
## Loosely based upon
|
## Loosely based upon
|
||||||
|
|
||||||
@@ -132,9 +151,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
* privatekey.Precompute() when signing?
|
* privatekey.Precompute() when signing?
|
||||||
* Last remaining RRs: APL, ATMA, A6 and NXT;
|
* Last remaining RRs: APL, ATMA, A6, NSAP and NXT.
|
||||||
* Missing in parsing: ISDN, UNSPEC, ATMA;
|
* Missing in parsing: ISDN, UNSPEC, NSAP and ATMA.
|
||||||
* CAA parsing is broken;
|
* NSEC(3) cover/match/closest enclose.
|
||||||
* NSEC(3) cover/match/closest enclose;
|
* Replies with TC bit are not parsed to the end.
|
||||||
* Replies with TC bit are not parsed to the end;
|
|
||||||
* Create IsMsg to validate a message before fully parsing it.
|
|
||||||
|
|||||||
297
vendor/github.com/miekg/dns/client.go
generated
vendored
297
vendor/github.com/miekg/dns/client.go
generated
vendored
@@ -4,12 +4,13 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dnsTimeout time.Duration = 2 * 1e9
|
const dnsTimeout time.Duration = 2 * time.Second
|
||||||
const tcpIdleTimeout time.Duration = 8 * time.Second
|
const tcpIdleTimeout time.Duration = 8 * time.Second
|
||||||
|
|
||||||
// A Conn represents a connection to a DNS server.
|
// A Conn represents a connection to a DNS server.
|
||||||
@@ -24,11 +25,12 @@ type Conn struct {
|
|||||||
|
|
||||||
// A Client defines parameters for a DNS client.
|
// A Client defines parameters for a DNS client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
|
Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
|
||||||
UDPSize uint16 // minimum receive buffer for UDP messages
|
UDPSize uint16 // minimum receive buffer for UDP messages
|
||||||
DialTimeout time.Duration // net.DialTimeout (ns), defaults to 2 * 1e9
|
TLSConfig *tls.Config // TLS connection configuration
|
||||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections (ns), defaults to 2 * 1e9
|
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
|
||||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections (ns), defaults to 2 * 1e9
|
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
|
||||||
|
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
|
||||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
||||||
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
|
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
|
||||||
group singleflight
|
group singleflight
|
||||||
@@ -37,14 +39,7 @@ type Client struct {
|
|||||||
// Exchange performs a synchronous UDP query. It sends the message m to the address
|
// Exchange performs a synchronous UDP query. It sends the message m to the address
|
||||||
// contained in a and waits for an reply. Exchange does not retry a failed query, nor
|
// contained in a and waits for an reply. Exchange does not retry a failed query, nor
|
||||||
// will it fall back to TCP in case of truncation.
|
// will it fall back to TCP in case of truncation.
|
||||||
// If you need to send a DNS message on an already existing connection, you can use the
|
// See client.Exchange for more information on setting larger buffer sizes.
|
||||||
// following:
|
|
||||||
//
|
|
||||||
// co := &dns.Conn{Conn: c} // c is your net.Conn
|
|
||||||
// co.WriteMsg(m)
|
|
||||||
// in, err := co.ReadMsg()
|
|
||||||
// co.Close()
|
|
||||||
//
|
|
||||||
func Exchange(m *Msg, a string) (r *Msg, err error) {
|
func Exchange(m *Msg, a string) (r *Msg, err error) {
|
||||||
var co *Conn
|
var co *Conn
|
||||||
co, err = DialTimeout("udp", a, dnsTimeout)
|
co, err = DialTimeout("udp", a, dnsTimeout)
|
||||||
@@ -53,12 +48,23 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer co.Close()
|
defer co.Close()
|
||||||
co.SetReadDeadline(time.Now().Add(dnsTimeout))
|
|
||||||
|
opt := m.IsEdns0()
|
||||||
|
// If EDNS0 is used use that for size.
|
||||||
|
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
||||||
|
co.UDPSize = opt.UDPSize()
|
||||||
|
}
|
||||||
|
|
||||||
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
|
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
|
||||||
if err = co.WriteMsg(m); err != nil {
|
if err = co.WriteMsg(m); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
co.SetReadDeadline(time.Now().Add(dnsTimeout))
|
||||||
r, err = co.ReadMsg()
|
r, err = co.ReadMsg()
|
||||||
|
if err == nil && r.Id != m.Id {
|
||||||
|
err = ErrId
|
||||||
|
}
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +85,9 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r, err = co.ReadMsg()
|
r, err = co.ReadMsg()
|
||||||
|
if err == nil && r.Id != m.Id {
|
||||||
|
err = ErrId
|
||||||
|
}
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +99,10 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
|||||||
//
|
//
|
||||||
// Exchange does not retry a failed query, nor will it fall back to TCP in
|
// Exchange does not retry a failed query, nor will it fall back to TCP in
|
||||||
// case of truncation.
|
// case of truncation.
|
||||||
|
// It is up to the caller to create a message that allows for larger responses to be
|
||||||
|
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
|
||||||
|
// buffer, see SetEdns0. Messsages without an OPT RR will fallback to the historic limit
|
||||||
|
// of 512 bytes.
|
||||||
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||||
if !c.SingleInflight {
|
if !c.SingleInflight {
|
||||||
return c.exchange(m, a)
|
return c.exchange(m, a)
|
||||||
@@ -115,31 +128,59 @@ func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
|||||||
return r, rtt, nil
|
return r, rtt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) dialTimeout() time.Duration {
|
||||||
timeout := dnsTimeout
|
|
||||||
var co *Conn
|
|
||||||
if c.DialTimeout != 0 {
|
if c.DialTimeout != 0 {
|
||||||
timeout = c.DialTimeout
|
return c.DialTimeout
|
||||||
}
|
}
|
||||||
if c.Net == "" {
|
return dnsTimeout
|
||||||
co, err = DialTimeout("udp", a, timeout)
|
}
|
||||||
|
|
||||||
|
func (c *Client) readTimeout() time.Duration {
|
||||||
|
if c.ReadTimeout != 0 {
|
||||||
|
return c.ReadTimeout
|
||||||
|
}
|
||||||
|
return dnsTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) writeTimeout() time.Duration {
|
||||||
|
if c.WriteTimeout != 0 {
|
||||||
|
return c.WriteTimeout
|
||||||
|
}
|
||||||
|
return dnsTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||||
|
var co *Conn
|
||||||
|
network := "udp"
|
||||||
|
tls := false
|
||||||
|
|
||||||
|
switch c.Net {
|
||||||
|
case "tcp-tls":
|
||||||
|
network = "tcp"
|
||||||
|
tls = true
|
||||||
|
case "tcp4-tls":
|
||||||
|
network = "tcp4"
|
||||||
|
tls = true
|
||||||
|
case "tcp6-tls":
|
||||||
|
network = "tcp6"
|
||||||
|
tls = true
|
||||||
|
default:
|
||||||
|
if c.Net != "" {
|
||||||
|
network = c.Net
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tls {
|
||||||
|
co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout())
|
||||||
} else {
|
} else {
|
||||||
co, err = DialTimeout(c.Net, a, timeout)
|
co, err = DialTimeout(network, a, c.dialTimeout())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
timeout = dnsTimeout
|
|
||||||
if c.ReadTimeout != 0 {
|
|
||||||
timeout = c.ReadTimeout
|
|
||||||
}
|
|
||||||
co.SetReadDeadline(time.Now().Add(timeout))
|
|
||||||
timeout = dnsTimeout
|
|
||||||
if c.WriteTimeout != 0 {
|
|
||||||
timeout = c.WriteTimeout
|
|
||||||
}
|
|
||||||
co.SetWriteDeadline(time.Now().Add(timeout))
|
|
||||||
defer co.Close()
|
defer co.Close()
|
||||||
|
|
||||||
opt := m.IsEdns0()
|
opt := m.IsEdns0()
|
||||||
// If EDNS0 is used use that for size.
|
// If EDNS0 is used use that for size.
|
||||||
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
||||||
@@ -149,11 +190,18 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
|||||||
if opt == nil && c.UDPSize >= MinMsgSize {
|
if opt == nil && c.UDPSize >= MinMsgSize {
|
||||||
co.UDPSize = c.UDPSize
|
co.UDPSize = c.UDPSize
|
||||||
}
|
}
|
||||||
|
|
||||||
co.TsigSecret = c.TsigSecret
|
co.TsigSecret = c.TsigSecret
|
||||||
|
co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
|
||||||
if err = co.WriteMsg(m); err != nil {
|
if err = co.WriteMsg(m); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
co.SetReadDeadline(time.Now().Add(c.readTimeout()))
|
||||||
r, err = co.ReadMsg()
|
r, err = co.ReadMsg()
|
||||||
|
if err == nil && r.Id != m.Id {
|
||||||
|
err = ErrId
|
||||||
|
}
|
||||||
return r, co.rtt, err
|
return r, co.rtt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,26 +209,21 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
|||||||
// If the received message contains a TSIG record the transaction
|
// If the received message contains a TSIG record the transaction
|
||||||
// signature is verified.
|
// signature is verified.
|
||||||
func (co *Conn) ReadMsg() (*Msg, error) {
|
func (co *Conn) ReadMsg() (*Msg, error) {
|
||||||
var p []byte
|
p, err := co.ReadMsgHeader(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
m := new(Msg)
|
m := new(Msg)
|
||||||
if _, ok := co.Conn.(*net.TCPConn); ok {
|
|
||||||
p = make([]byte, MaxMsgSize)
|
|
||||||
} else {
|
|
||||||
if co.UDPSize >= 512 {
|
|
||||||
p = make([]byte, co.UDPSize)
|
|
||||||
} else {
|
|
||||||
p = make([]byte, MinMsgSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n, err := co.Read(p)
|
|
||||||
if err != nil && n == 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
p = p[:n]
|
|
||||||
if err := m.Unpack(p); err != nil {
|
if err := m.Unpack(p); err != nil {
|
||||||
|
// If ErrTruncated was returned, we still want to allow the user to use
|
||||||
|
// the message, but naively they can just check err if they don't want
|
||||||
|
// to use a truncated message
|
||||||
|
if err == ErrTruncated {
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
co.rtt = time.Since(co.t)
|
|
||||||
if t := m.IsTsig(); t != nil {
|
if t := m.IsTsig(); t != nil {
|
||||||
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
||||||
return m, ErrSecret
|
return m, ErrSecret
|
||||||
@@ -191,6 +234,86 @@ func (co *Conn) ReadMsg() (*Msg, error) {
|
|||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadMsgHeader reads a DNS message, parses and populates hdr (when hdr is not nil).
|
||||||
|
// Returns message as a byte slice to be parsed with Msg.Unpack later on.
|
||||||
|
// Note that error handling on the message body is not possible as only the header is parsed.
|
||||||
|
func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
p []byte
|
||||||
|
n int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch t := co.Conn.(type) {
|
||||||
|
case *net.TCPConn, *tls.Conn:
|
||||||
|
r := t.(io.Reader)
|
||||||
|
|
||||||
|
// First two bytes specify the length of the entire message.
|
||||||
|
l, err := tcpMsgLen(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p = make([]byte, l)
|
||||||
|
n, err = tcpRead(r, p)
|
||||||
|
co.rtt = time.Since(co.t)
|
||||||
|
default:
|
||||||
|
if co.UDPSize > MinMsgSize {
|
||||||
|
p = make([]byte, co.UDPSize)
|
||||||
|
} else {
|
||||||
|
p = make([]byte, MinMsgSize)
|
||||||
|
}
|
||||||
|
n, err = co.Read(p)
|
||||||
|
co.rtt = time.Since(co.t)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if n < headerSize {
|
||||||
|
return nil, ErrShortRead
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p[:n]
|
||||||
|
if hdr != nil {
|
||||||
|
if _, err = UnpackStruct(hdr, p, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
|
||||||
|
func tcpMsgLen(t io.Reader) (int, error) {
|
||||||
|
p := []byte{0, 0}
|
||||||
|
n, err := t.Read(p)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if n != 2 {
|
||||||
|
return 0, ErrShortRead
|
||||||
|
}
|
||||||
|
l, _ := unpackUint16(p, 0)
|
||||||
|
if l == 0 {
|
||||||
|
return 0, ErrShortRead
|
||||||
|
}
|
||||||
|
return int(l), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tcpRead calls TCPConn.Read enough times to fill allocated buffer.
|
||||||
|
func tcpRead(t io.Reader, p []byte) (int, error) {
|
||||||
|
n, err := t.Read(p)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
for n < len(p) {
|
||||||
|
j, err := t.Read(p[n:])
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n += j
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
// Read implements the net.Conn read method.
|
// Read implements the net.Conn read method.
|
||||||
func (co *Conn) Read(p []byte) (n int, err error) {
|
func (co *Conn) Read(p []byte) (n int, err error) {
|
||||||
if co.Conn == nil {
|
if co.Conn == nil {
|
||||||
@@ -199,32 +322,18 @@ func (co *Conn) Read(p []byte) (n int, err error) {
|
|||||||
if len(p) < 2 {
|
if len(p) < 2 {
|
||||||
return 0, io.ErrShortBuffer
|
return 0, io.ErrShortBuffer
|
||||||
}
|
}
|
||||||
if t, ok := co.Conn.(*net.TCPConn); ok {
|
switch t := co.Conn.(type) {
|
||||||
n, err = t.Read(p[0:2])
|
case *net.TCPConn, *tls.Conn:
|
||||||
if err != nil || n != 2 {
|
r := t.(io.Reader)
|
||||||
return n, err
|
|
||||||
|
l, err := tcpMsgLen(r)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
l, _ := unpackUint16(p[0:2], 0)
|
if l > len(p) {
|
||||||
if l == 0 {
|
|
||||||
return 0, ErrShortRead
|
|
||||||
}
|
|
||||||
if int(l) > len(p) {
|
|
||||||
return int(l), io.ErrShortBuffer
|
return int(l), io.ErrShortBuffer
|
||||||
}
|
}
|
||||||
n, err = t.Read(p[:l])
|
return tcpRead(r, p[:l])
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
i := n
|
|
||||||
for i < int(l) {
|
|
||||||
j, err := t.Read(p[i:int(l)])
|
|
||||||
if err != nil {
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
i += j
|
|
||||||
}
|
|
||||||
n = i
|
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
// UDP connection
|
// UDP connection
|
||||||
n, err = co.Conn.Read(p)
|
n, err = co.Conn.Read(p)
|
||||||
@@ -234,7 +343,7 @@ func (co *Conn) Read(p []byte) (n int, err error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteMsg sends a message throught the connection co.
|
// WriteMsg sends a message through the connection co.
|
||||||
// If the message m contains a TSIG record the transaction
|
// If the message m contains a TSIG record the transaction
|
||||||
// signature is calculated.
|
// signature is calculated.
|
||||||
func (co *Conn) WriteMsg(m *Msg) (err error) {
|
func (co *Conn) WriteMsg(m *Msg) (err error) {
|
||||||
@@ -245,7 +354,7 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
|
|||||||
return ErrSecret
|
return ErrSecret
|
||||||
}
|
}
|
||||||
out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
|
out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
|
||||||
// Set for the next read, allthough only used in zone transfers
|
// Set for the next read, although only used in zone transfers
|
||||||
co.tsigRequestMAC = mac
|
co.tsigRequestMAC = mac
|
||||||
} else {
|
} else {
|
||||||
out, err = m.Pack()
|
out, err = m.Pack()
|
||||||
@@ -262,7 +371,10 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
|
|||||||
|
|
||||||
// Write implements the net.Conn Write method.
|
// Write implements the net.Conn Write method.
|
||||||
func (co *Conn) Write(p []byte) (n int, err error) {
|
func (co *Conn) Write(p []byte) (n int, err error) {
|
||||||
if t, ok := co.Conn.(*net.TCPConn); ok {
|
switch t := co.Conn.(type) {
|
||||||
|
case *net.TCPConn, *tls.Conn:
|
||||||
|
w := t.(io.Writer)
|
||||||
|
|
||||||
lp := len(p)
|
lp := len(p)
|
||||||
if lp < 2 {
|
if lp < 2 {
|
||||||
return 0, io.ErrShortBuffer
|
return 0, io.ErrShortBuffer
|
||||||
@@ -273,7 +385,7 @@ func (co *Conn) Write(p []byte) (n int, err error) {
|
|||||||
l := make([]byte, 2, lp+2)
|
l := make([]byte, 2, lp+2)
|
||||||
l[0], l[1] = packUint16(uint16(lp))
|
l[0], l[1] = packUint16(uint16(lp))
|
||||||
p = append(l, p...)
|
p = append(l, p...)
|
||||||
n, err := io.Copy(t, bytes.NewReader(p))
|
n, err := io.Copy(w, bytes.NewReader(p))
|
||||||
return int(n), err
|
return int(n), err
|
||||||
}
|
}
|
||||||
n, err = co.Conn.(*net.UDPConn).Write(p)
|
n, err = co.Conn.(*net.UDPConn).Write(p)
|
||||||
@@ -290,7 +402,7 @@ func Dial(network, address string) (conn *Conn, err error) {
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dialtimeout acts like Dial but takes a timeout.
|
// DialTimeout acts like Dial but takes a timeout.
|
||||||
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
|
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
|
||||||
conn = new(Conn)
|
conn = new(Conn)
|
||||||
conn.Conn, err = net.DialTimeout(network, address, timeout)
|
conn.Conn, err = net.DialTimeout(network, address, timeout)
|
||||||
@@ -300,20 +412,25 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements the net.Conn Close method.
|
// DialWithTLS connects to the address on the named network with TLS.
|
||||||
func (co *Conn) Close() error { return co.Conn.Close() }
|
func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) {
|
||||||
|
conn = new(Conn)
|
||||||
|
conn.Conn, err = tls.Dial(network, address, tlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
// LocalAddr implements the net.Conn LocalAddr method.
|
// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
|
||||||
func (co *Conn) LocalAddr() net.Addr { return co.Conn.LocalAddr() }
|
func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) {
|
||||||
|
var dialer net.Dialer
|
||||||
|
dialer.Timeout = timeout
|
||||||
|
|
||||||
// RemoteAddr implements the net.Conn RemoteAddr method.
|
conn = new(Conn)
|
||||||
func (co *Conn) RemoteAddr() net.Addr { return co.Conn.RemoteAddr() }
|
conn.Conn, err = tls.DialWithDialer(&dialer, network, address, tlsConfig)
|
||||||
|
if err != nil {
|
||||||
// SetDeadline implements the net.Conn SetDeadline method.
|
return nil, err
|
||||||
func (co *Conn) SetDeadline(t time.Time) error { return co.Conn.SetDeadline(t) }
|
}
|
||||||
|
return conn, nil
|
||||||
// SetReadDeadline implements the net.Conn SetReadDeadline method.
|
}
|
||||||
func (co *Conn) SetReadDeadline(t time.Time) error { return co.Conn.SetReadDeadline(t) }
|
|
||||||
|
|
||||||
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
|
|
||||||
func (co *Conn) SetWriteDeadline(t time.Time) error { return co.Conn.SetWriteDeadline(t) }
|
|
||||||
|
|||||||
11
vendor/github.com/miekg/dns/clientconfig.go
generated
vendored
11
vendor/github.com/miekg/dns/clientconfig.go
generated
vendored
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Wraps the contents of the /etc/resolv.conf.
|
// ClientConfig wraps the contents of the /etc/resolv.conf file.
|
||||||
type ClientConfig struct {
|
type ClientConfig struct {
|
||||||
Servers []string // servers to use
|
Servers []string // servers to use
|
||||||
Search []string // suffixes to append to local name
|
Search []string // suffixes to append to local name
|
||||||
@@ -26,14 +26,19 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
c := new(ClientConfig)
|
c := new(ClientConfig)
|
||||||
b := bufio.NewReader(file)
|
scanner := bufio.NewScanner(file)
|
||||||
c.Servers = make([]string, 0)
|
c.Servers = make([]string, 0)
|
||||||
c.Search = make([]string, 0)
|
c.Search = make([]string, 0)
|
||||||
c.Port = "53"
|
c.Port = "53"
|
||||||
c.Ndots = 1
|
c.Ndots = 1
|
||||||
c.Timeout = 5
|
c.Timeout = 5
|
||||||
c.Attempts = 2
|
c.Attempts = 2
|
||||||
for line, ok := b.ReadString('\n'); ok == nil; line, ok = b.ReadString('\n') {
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
line := scanner.Text()
|
||||||
f := strings.Fields(line)
|
f := strings.Fields(line)
|
||||||
if len(f) < 1 {
|
if len(f) < 1 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
54
vendor/github.com/miekg/dns/defaults.go
generated
vendored
54
vendor/github.com/miekg/dns/defaults.go
generated
vendored
@@ -24,7 +24,9 @@ func (dns *Msg) SetReply(request *Msg) *Msg {
|
|||||||
return dns
|
return dns
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetQuestion creates a question message.
|
// SetQuestion creates a question message, it sets the Question
|
||||||
|
// section, generates an Id and sets the RecursionDesired (RD)
|
||||||
|
// bit to true.
|
||||||
func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
|
func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
|
||||||
dns.Id = Id()
|
dns.Id = Id()
|
||||||
dns.RecursionDesired = true
|
dns.RecursionDesired = true
|
||||||
@@ -33,7 +35,9 @@ func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
|
|||||||
return dns
|
return dns
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNotify creates a notify message.
|
// SetNotify creates a notify message, it sets the Question
|
||||||
|
// section, generates an Id and sets the Authoritative (AA)
|
||||||
|
// bit to true.
|
||||||
func (dns *Msg) SetNotify(z string) *Msg {
|
func (dns *Msg) SetNotify(z string) *Msg {
|
||||||
dns.Opcode = OpcodeNotify
|
dns.Opcode = OpcodeNotify
|
||||||
dns.Authoritative = true
|
dns.Authoritative = true
|
||||||
@@ -73,13 +77,15 @@ func (dns *Msg) SetUpdate(z string) *Msg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetIxfr creates message for requesting an IXFR.
|
// SetIxfr creates message for requesting an IXFR.
|
||||||
func (dns *Msg) SetIxfr(z string, serial uint32) *Msg {
|
func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
|
||||||
dns.Id = Id()
|
dns.Id = Id()
|
||||||
dns.Question = make([]Question, 1)
|
dns.Question = make([]Question, 1)
|
||||||
dns.Ns = make([]RR, 1)
|
dns.Ns = make([]RR, 1)
|
||||||
s := new(SOA)
|
s := new(SOA)
|
||||||
s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
|
s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
|
||||||
s.Serial = serial
|
s.Serial = serial
|
||||||
|
s.Ns = ns
|
||||||
|
s.Mbox = mbox
|
||||||
dns.Question[0] = Question{z, TypeIXFR, ClassINET}
|
dns.Question[0] = Question{z, TypeIXFR, ClassINET}
|
||||||
dns.Ns[0] = s
|
dns.Ns[0] = s
|
||||||
return dns
|
return dns
|
||||||
@@ -144,11 +150,14 @@ func (dns *Msg) IsEdns0() *OPT {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDomainName checks if s is a valid domainname, it returns
|
// IsDomainName checks if s is a valid domain name, it returns the number of
|
||||||
// the number of labels and true, when a domain name is valid.
|
// labels and true, when a domain name is valid. Note that non fully qualified
|
||||||
// Note that non fully qualified domain name is considered valid, in this case the
|
// domain name is considered valid, in this case the last label is counted in
|
||||||
// last label is counted in the number of labels.
|
// the number of labels. When false is returned the number of labels is not
|
||||||
// When false is returned the number of labels is not defined.
|
// defined. Also note that this function is extremely liberal; almost any
|
||||||
|
// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
|
||||||
|
// label fits in 63 characters, but there is no length check for the entire
|
||||||
|
// string s. I.e. a domain name longer than 255 characters is considered valid.
|
||||||
func IsDomainName(s string) (labels int, ok bool) {
|
func IsDomainName(s string) (labels int, ok bool) {
|
||||||
_, labels, err := packDomainName(s, nil, 0, nil, false)
|
_, labels, err := packDomainName(s, nil, 0, nil, false)
|
||||||
return labels, err == nil
|
return labels, err == nil
|
||||||
@@ -182,7 +191,34 @@ func IsFqdn(s string) bool {
|
|||||||
return s[l-1] == '.'
|
return s[l-1] == '.'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fqdns return the fully qualified domain name from s.
|
// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
|
||||||
|
// This means the RRs need to have the same type, name, and class. Returns true
|
||||||
|
// if the RR set is valid, otherwise false.
|
||||||
|
func IsRRset(rrset []RR) bool {
|
||||||
|
if len(rrset) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(rrset) == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
rrHeader := rrset[0].Header()
|
||||||
|
rrType := rrHeader.Rrtype
|
||||||
|
rrClass := rrHeader.Class
|
||||||
|
rrName := rrHeader.Name
|
||||||
|
|
||||||
|
for _, rr := range rrset[1:] {
|
||||||
|
curRRHeader := rr.Header()
|
||||||
|
if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName {
|
||||||
|
// Mismatch between the records, so this is not a valid rrset for
|
||||||
|
//signing/verifying
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fqdn return the fully qualified domain name from s.
|
||||||
// If s is already fully qualified, it behaves as the identity function.
|
// If s is already fully qualified, it behaves as the identity function.
|
||||||
func Fqdn(s string) string {
|
func Fqdn(s string) string {
|
||||||
if IsFqdn(s) {
|
if IsFqdn(s) {
|
||||||
|
|||||||
119
vendor/github.com/miekg/dns/dns.go
generated
vendored
119
vendor/github.com/miekg/dns/dns.go
generated
vendored
@@ -1,108 +1,16 @@
|
|||||||
// Package dns implements a full featured interface to the Domain Name System.
|
|
||||||
// Server- and client-side programming is supported.
|
|
||||||
// The package allows complete control over what is send out to the DNS. The package
|
|
||||||
// API follows the less-is-more principle, by presenting a small, clean interface.
|
|
||||||
//
|
|
||||||
// The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
|
|
||||||
// TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
|
|
||||||
// Note that domain names MUST be fully qualified, before sending them, unqualified
|
|
||||||
// names in a message will result in a packing failure.
|
|
||||||
//
|
|
||||||
// Resource records are native types. They are not stored in wire format.
|
|
||||||
// Basic usage pattern for creating a new resource record:
|
|
||||||
//
|
|
||||||
// r := new(dns.MX)
|
|
||||||
// r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
|
|
||||||
// r.Preference = 10
|
|
||||||
// r.Mx = "mx.miek.nl."
|
|
||||||
//
|
|
||||||
// Or directly from a string:
|
|
||||||
//
|
|
||||||
// mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
|
|
||||||
//
|
|
||||||
// Or when the default TTL (3600) and class (IN) suit you:
|
|
||||||
//
|
|
||||||
// mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
|
|
||||||
//
|
|
||||||
// Or even:
|
|
||||||
//
|
|
||||||
// mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
|
|
||||||
//
|
|
||||||
// In the DNS messages are exchanged, these messages contain resource
|
|
||||||
// records (sets). Use pattern for creating a message:
|
|
||||||
//
|
|
||||||
// m := new(dns.Msg)
|
|
||||||
// m.SetQuestion("miek.nl.", dns.TypeMX)
|
|
||||||
//
|
|
||||||
// Or when not certain if the domain name is fully qualified:
|
|
||||||
//
|
|
||||||
// m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
|
|
||||||
//
|
|
||||||
// The message m is now a message with the question section set to ask
|
|
||||||
// the MX records for the miek.nl. zone.
|
|
||||||
//
|
|
||||||
// The following is slightly more verbose, but more flexible:
|
|
||||||
//
|
|
||||||
// m1 := new(dns.Msg)
|
|
||||||
// m1.Id = dns.Id()
|
|
||||||
// m1.RecursionDesired = true
|
|
||||||
// m1.Question = make([]dns.Question, 1)
|
|
||||||
// m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
|
|
||||||
//
|
|
||||||
// After creating a message it can be send.
|
|
||||||
// Basic use pattern for synchronous querying the DNS at a
|
|
||||||
// server configured on 127.0.0.1 and port 53:
|
|
||||||
//
|
|
||||||
// c := new(dns.Client)
|
|
||||||
// in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
|
|
||||||
//
|
|
||||||
// Suppressing
|
|
||||||
// multiple outstanding queries (with the same question, type and class) is as easy as setting:
|
|
||||||
//
|
|
||||||
// c.SingleInflight = true
|
|
||||||
//
|
|
||||||
// If these "advanced" features are not needed, a simple UDP query can be send,
|
|
||||||
// with:
|
|
||||||
//
|
|
||||||
// in, err := dns.Exchange(m1, "127.0.0.1:53")
|
|
||||||
//
|
|
||||||
// When this functions returns you will get dns message. A dns message consists
|
|
||||||
// out of four sections.
|
|
||||||
// The question section: in.Question, the answer section: in.Answer,
|
|
||||||
// the authority section: in.Ns and the additional section: in.Extra.
|
|
||||||
//
|
|
||||||
// Each of these sections (except the Question section) contain a []RR. Basic
|
|
||||||
// use pattern for accessing the rdata of a TXT RR as the first RR in
|
|
||||||
// the Answer section:
|
|
||||||
//
|
|
||||||
// if t, ok := in.Answer[0].(*dns.TXT); ok {
|
|
||||||
// // do something with t.Txt
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Domain Name and TXT Character String Representations
|
|
||||||
//
|
|
||||||
// Both domain names and TXT character strings are converted to presentation
|
|
||||||
// form both when unpacked and when converted to strings.
|
|
||||||
//
|
|
||||||
// For TXT character strings, tabs, carriage returns and line feeds will be
|
|
||||||
// converted to \t, \r and \n respectively. Back slashes and quotations marks
|
|
||||||
// will be escaped. Bytes below 32 and above 127 will be converted to \DDD
|
|
||||||
// form.
|
|
||||||
//
|
|
||||||
// For domain names, in addition to the above rules brackets, periods,
|
|
||||||
// spaces, semicolons and the at symbol are escaped.
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import "strconv"
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
||||||
DefaultMsgSize = 4096 // Standard default for larger than 512 bytes.
|
// DefaultMsgSize is the standard default for messages larger than 512 bytes.
|
||||||
MinMsgSize = 512 // Minimal size of a DNS packet.
|
DefaultMsgSize = 4096
|
||||||
MaxMsgSize = 65536 // Largest possible DNS packet.
|
// MinMsgSize is the minimal size of a DNS packet.
|
||||||
defaultTtl = 3600 // Default TTL.
|
MinMsgSize = 512
|
||||||
|
// MaxMsgSize is the largest possible DNS packet.
|
||||||
|
MaxMsgSize = 65535
|
||||||
|
defaultTtl = 3600 // Default internal TTL.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error represents a DNS error
|
// Error represents a DNS error
|
||||||
@@ -124,13 +32,11 @@ type RR interface {
|
|||||||
String() string
|
String() string
|
||||||
// copy returns a copy of the RR
|
// copy returns a copy of the RR
|
||||||
copy() RR
|
copy() RR
|
||||||
// len returns the length (in octects) of the uncompressed RR in wire format.
|
// len returns the length (in octets) of the uncompressed RR in wire format.
|
||||||
len() int
|
len() int
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNS resource records.
|
// RR_Header is the header all DNS resource records share.
|
||||||
// There are many types of RRs,
|
|
||||||
// but they all share the same header.
|
|
||||||
type RR_Header struct {
|
type RR_Header struct {
|
||||||
Name string `dns:"cdomain-name"`
|
Name string `dns:"cdomain-name"`
|
||||||
Rrtype uint16
|
Rrtype uint16
|
||||||
@@ -139,9 +45,10 @@ type RR_Header struct {
|
|||||||
Rdlength uint16 // length of data after header
|
Rdlength uint16 // length of data after header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header returns itself. This is here to make RR_Header implement the RR interface.
|
||||||
func (h *RR_Header) Header() *RR_Header { return h }
|
func (h *RR_Header) Header() *RR_Header { return h }
|
||||||
|
|
||||||
// Just to imlement the RR interface
|
// Just to imlement the RR interface.
|
||||||
func (h *RR_Header) copy() RR { return nil }
|
func (h *RR_Header) copy() RR { return nil }
|
||||||
|
|
||||||
func (h *RR_Header) copyHeader() *RR_Header {
|
func (h *RR_Header) copyHeader() *RR_Header {
|
||||||
|
|||||||
464
vendor/github.com/miekg/dns/dnssec.go
generated
vendored
464
vendor/github.com/miekg/dns/dnssec.go
generated
vendored
@@ -1,16 +1,3 @@
|
|||||||
// DNSSEC
|
|
||||||
//
|
|
||||||
// DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
|
|
||||||
// uses public key cryptography to sign resource records. The
|
|
||||||
// public keys are stored in DNSKEY records and the signatures in RRSIG records.
|
|
||||||
//
|
|
||||||
// Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
|
|
||||||
// to an request.
|
|
||||||
//
|
|
||||||
// m := new(dns.Msg)
|
|
||||||
// m.SetEdns0(4096, true)
|
|
||||||
//
|
|
||||||
// Signature generation, signature verification and key generation are all supported.
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -19,15 +6,14 @@ import (
|
|||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/md5"
|
_ "crypto/md5"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/sha1"
|
_ "crypto/sha1"
|
||||||
"crypto/sha256"
|
_ "crypto/sha256"
|
||||||
"crypto/sha512"
|
_ "crypto/sha512"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -56,6 +42,38 @@ const (
|
|||||||
PRIVATEOID uint8 = 254
|
PRIVATEOID uint8 = 254
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Map for algorithm names.
|
||||||
|
var AlgorithmToString = map[uint8]string{
|
||||||
|
RSAMD5: "RSAMD5",
|
||||||
|
DH: "DH",
|
||||||
|
DSA: "DSA",
|
||||||
|
RSASHA1: "RSASHA1",
|
||||||
|
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
|
||||||
|
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
|
||||||
|
RSASHA256: "RSASHA256",
|
||||||
|
RSASHA512: "RSASHA512",
|
||||||
|
ECCGOST: "ECC-GOST",
|
||||||
|
ECDSAP256SHA256: "ECDSAP256SHA256",
|
||||||
|
ECDSAP384SHA384: "ECDSAP384SHA384",
|
||||||
|
INDIRECT: "INDIRECT",
|
||||||
|
PRIVATEDNS: "PRIVATEDNS",
|
||||||
|
PRIVATEOID: "PRIVATEOID",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of algorithm strings.
|
||||||
|
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||||
|
|
||||||
|
// Map of algorithm crypto hashes.
|
||||||
|
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||||
|
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||||
|
RSASHA1: crypto.SHA1,
|
||||||
|
RSASHA1NSEC3SHA1: crypto.SHA1,
|
||||||
|
RSASHA256: crypto.SHA256,
|
||||||
|
ECDSAP256SHA256: crypto.SHA256,
|
||||||
|
ECDSAP384SHA384: crypto.SHA384,
|
||||||
|
RSASHA512: crypto.SHA512,
|
||||||
|
}
|
||||||
|
|
||||||
// DNSSEC hashing algorithm codes.
|
// DNSSEC hashing algorithm codes.
|
||||||
const (
|
const (
|
||||||
_ uint8 = iota
|
_ uint8 = iota
|
||||||
@@ -66,6 +84,18 @@ const (
|
|||||||
SHA512 // Experimental
|
SHA512 // Experimental
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Map for hash names.
|
||||||
|
var HashToString = map[uint8]string{
|
||||||
|
SHA1: "SHA1",
|
||||||
|
SHA256: "SHA256",
|
||||||
|
GOST94: "GOST94",
|
||||||
|
SHA384: "SHA384",
|
||||||
|
SHA512: "SHA512",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of hash strings.
|
||||||
|
var StringToHash = reverseInt8(HashToString)
|
||||||
|
|
||||||
// DNSKEY flag values.
|
// DNSKEY flag values.
|
||||||
const (
|
const (
|
||||||
SEP = 1
|
SEP = 1
|
||||||
@@ -74,7 +104,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// The RRSIG needs to be converted to wireformat with some of
|
// The RRSIG needs to be converted to wireformat with some of
|
||||||
// the rdata (the signature) missing. Use this struct to easy
|
// the rdata (the signature) missing. Use this struct to ease
|
||||||
// the conversion (and re-use the pack/unpack functions).
|
// the conversion (and re-use the pack/unpack functions).
|
||||||
type rrsigWireFmt struct {
|
type rrsigWireFmt struct {
|
||||||
TypeCovered uint16
|
TypeCovered uint16
|
||||||
@@ -182,35 +212,49 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
|
|||||||
// digest buffer
|
// digest buffer
|
||||||
digest := append(owner, wire...) // another copy
|
digest := append(owner, wire...) // another copy
|
||||||
|
|
||||||
|
var hash crypto.Hash
|
||||||
switch h {
|
switch h {
|
||||||
case SHA1:
|
case SHA1:
|
||||||
s := sha1.New()
|
hash = crypto.SHA1
|
||||||
io.WriteString(s, string(digest))
|
|
||||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
|
||||||
case SHA256:
|
case SHA256:
|
||||||
s := sha256.New()
|
hash = crypto.SHA256
|
||||||
io.WriteString(s, string(digest))
|
|
||||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
|
||||||
case SHA384:
|
case SHA384:
|
||||||
s := sha512.New384()
|
hash = crypto.SHA384
|
||||||
io.WriteString(s, string(digest))
|
case SHA512:
|
||||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
hash = crypto.SHA512
|
||||||
case GOST94:
|
|
||||||
/* I have no clue */
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s := hash.New()
|
||||||
|
s.Write(digest)
|
||||||
|
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||||
return ds
|
return ds
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs an RRSet. The signature needs to be filled in with
|
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
|
||||||
// the values: Inception, Expiration, KeyTag, SignerName and Algorithm.
|
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
|
||||||
// The rest is copied from the RRset. Sign returns true when the signing went OK,
|
c := &CDNSKEY{DNSKEY: *k}
|
||||||
// otherwise false.
|
c.Hdr = *k.Hdr.copyHeader()
|
||||||
// There is no check if RRSet is a proper (RFC 2181) RRSet.
|
c.Hdr.Rrtype = TypeCDNSKEY
|
||||||
// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset
|
return c
|
||||||
// is used as the OrigTTL.
|
}
|
||||||
func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
|
|
||||||
|
// ToCDS converts a DS record to a CDS record.
|
||||||
|
func (d *DS) ToCDS() *CDS {
|
||||||
|
c := &CDS{DS: *d}
|
||||||
|
c.Hdr = *d.Hdr.copyHeader()
|
||||||
|
c.Hdr.Rrtype = TypeCDS
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs an RRSet. The signature needs to be filled in with the values:
|
||||||
|
// Inception, Expiration, KeyTag, SignerName and Algorithm. The rest is copied
|
||||||
|
// from the RRset. Sign returns a non-nill error when the signing went OK.
|
||||||
|
// There is no check if RRSet is a proper (RFC 2181) RRSet. If OrigTTL is non
|
||||||
|
// zero, it is used as-is, otherwise the TTL of the RRset is used as the
|
||||||
|
// OrigTTL.
|
||||||
|
func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
||||||
if k == nil {
|
if k == nil {
|
||||||
return ErrPrivKey
|
return ErrPrivKey
|
||||||
}
|
}
|
||||||
@@ -256,72 +300,72 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
|
|||||||
}
|
}
|
||||||
signdata = append(signdata, wire...)
|
signdata = append(signdata, wire...)
|
||||||
|
|
||||||
var sighash []byte
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
var h hash.Hash
|
if !ok {
|
||||||
var ch crypto.Hash // Only need for RSA
|
|
||||||
var intlen int
|
|
||||||
switch rr.Algorithm {
|
|
||||||
case DSA, DSANSEC3SHA1:
|
|
||||||
// Implicit in the ParameterSizes
|
|
||||||
case RSASHA1, RSASHA1NSEC3SHA1:
|
|
||||||
h = sha1.New()
|
|
||||||
ch = crypto.SHA1
|
|
||||||
case RSASHA256, ECDSAP256SHA256:
|
|
||||||
h = sha256.New()
|
|
||||||
ch = crypto.SHA256
|
|
||||||
intlen = 32
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
h = sha512.New384()
|
|
||||||
intlen = 48
|
|
||||||
case RSASHA512:
|
|
||||||
h = sha512.New()
|
|
||||||
ch = crypto.SHA512
|
|
||||||
case RSAMD5:
|
|
||||||
fallthrough // Deprecated in RFC 6725
|
|
||||||
default:
|
|
||||||
return ErrAlg
|
return ErrAlg
|
||||||
}
|
}
|
||||||
io.WriteString(h, string(signdata))
|
|
||||||
sighash = h.Sum(nil)
|
|
||||||
|
|
||||||
switch p := k.(type) {
|
h := hash.New()
|
||||||
case *dsa.PrivateKey:
|
h.Write(signdata)
|
||||||
r1, s1, err := dsa.Sign(rand.Reader, p, sighash)
|
|
||||||
if err != nil {
|
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
signature := []byte{0x4D} // T value, here the ASCII M for Miek (not used in DNSSEC)
|
|
||||||
signature = append(signature, intToBytes(r1, 20)...)
|
|
||||||
signature = append(signature, intToBytes(s1, 20)...)
|
|
||||||
rr.Signature = toBase64(signature)
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
// We can use nil as rand.Reader here (says AGL)
|
|
||||||
signature, err := rsa.SignPKCS1v15(nil, p, ch, sighash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rr.Signature = toBase64(signature)
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
r1, s1, err := ecdsa.Sign(rand.Reader, p, sighash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
signature := intToBytes(r1, intlen)
|
|
||||||
signature = append(signature, intToBytes(s1, intlen)...)
|
|
||||||
rr.Signature = toBase64(signature)
|
|
||||||
default:
|
|
||||||
// Not given the correct key
|
|
||||||
return ErrKeyAlg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rr.Signature = toBase64(signature)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
|
||||||
|
signature, err := k.Sign(rand.Reader, hashed, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch alg {
|
||||||
|
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
|
||||||
|
return signature, nil
|
||||||
|
|
||||||
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
|
ecdsaSignature := &struct {
|
||||||
|
R, S *big.Int
|
||||||
|
}{}
|
||||||
|
if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var intlen int
|
||||||
|
switch alg {
|
||||||
|
case ECDSAP256SHA256:
|
||||||
|
intlen = 32
|
||||||
|
case ECDSAP384SHA384:
|
||||||
|
intlen = 48
|
||||||
|
}
|
||||||
|
|
||||||
|
signature := intToBytes(ecdsaSignature.R, intlen)
|
||||||
|
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
|
||||||
|
return signature, nil
|
||||||
|
|
||||||
|
// There is no defined interface for what a DSA backed crypto.Signer returns
|
||||||
|
case DSA, DSANSEC3SHA1:
|
||||||
|
// t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
|
||||||
|
// signature := []byte{byte(t)}
|
||||||
|
// signature = append(signature, intToBytes(r1, 20)...)
|
||||||
|
// signature = append(signature, intToBytes(s1, 20)...)
|
||||||
|
// rr.Signature = signature
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrAlg
|
||||||
|
}
|
||||||
|
|
||||||
// Verify validates an RRSet with the signature and key. This is only the
|
// Verify validates an RRSet with the signature and key. This is only the
|
||||||
// cryptographic test, the signature validity period must be checked separately.
|
// cryptographic test, the signature validity period must be checked separately.
|
||||||
// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
|
// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
|
||||||
func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
||||||
// First the easy checks
|
// First the easy checks
|
||||||
if len(rrset) == 0 {
|
if !IsRRset(rrset) {
|
||||||
return ErrRRset
|
return ErrRRset
|
||||||
}
|
}
|
||||||
if rr.KeyTag != k.KeyTag() {
|
if rr.KeyTag != k.KeyTag() {
|
||||||
@@ -339,14 +383,17 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||||||
if k.Protocol != 3 {
|
if k.Protocol != 3 {
|
||||||
return ErrKey
|
return ErrKey
|
||||||
}
|
}
|
||||||
for _, r := range rrset {
|
|
||||||
if r.Header().Class != rr.Hdr.Class {
|
// IsRRset checked that we have at least one RR and that the RRs in
|
||||||
return ErrRRset
|
// the set have consistent type, class, and name. Also check that type and
|
||||||
}
|
// class matches the RRSIG record.
|
||||||
if r.Header().Rrtype != rr.TypeCovered {
|
if rrset[0].Header().Class != rr.Hdr.Class {
|
||||||
return ErrRRset
|
return ErrRRset
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if rrset[0].Header().Rrtype != rr.TypeCovered {
|
||||||
|
return ErrRRset
|
||||||
|
}
|
||||||
|
|
||||||
// RFC 4035 5.3.2. Reconstructing the Signed Data
|
// RFC 4035 5.3.2. Reconstructing the Signed Data
|
||||||
// Copy the sig, except the rrsig data
|
// Copy the sig, except the rrsig data
|
||||||
sigwire := new(rrsigWireFmt)
|
sigwire := new(rrsigWireFmt)
|
||||||
@@ -373,8 +420,13 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||||||
|
|
||||||
sigbuf := rr.sigBuf() // Get the binary signature data
|
sigbuf := rr.sigBuf() // Get the binary signature data
|
||||||
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
||||||
// TODO(mg)
|
// TODO(miek)
|
||||||
// remove the domain name and assume its our
|
// remove the domain name and assume its ours?
|
||||||
|
}
|
||||||
|
|
||||||
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
|
if !ok {
|
||||||
|
return ErrAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rr.Algorithm {
|
switch rr.Algorithm {
|
||||||
@@ -384,57 +436,37 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||||||
if pubkey == nil {
|
if pubkey == nil {
|
||||||
return ErrKey
|
return ErrKey
|
||||||
}
|
}
|
||||||
// Setup the hash as defined for this alg.
|
|
||||||
var h hash.Hash
|
h := hash.New()
|
||||||
var ch crypto.Hash
|
h.Write(signeddata)
|
||||||
switch rr.Algorithm {
|
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
|
||||||
case RSAMD5:
|
|
||||||
h = md5.New()
|
|
||||||
ch = crypto.MD5
|
|
||||||
case RSASHA1, RSASHA1NSEC3SHA1:
|
|
||||||
h = sha1.New()
|
|
||||||
ch = crypto.SHA1
|
|
||||||
case RSASHA256:
|
|
||||||
h = sha256.New()
|
|
||||||
ch = crypto.SHA256
|
|
||||||
case RSASHA512:
|
|
||||||
h = sha512.New()
|
|
||||||
ch = crypto.SHA512
|
|
||||||
}
|
|
||||||
io.WriteString(h, string(signeddata))
|
|
||||||
sighash := h.Sum(nil)
|
|
||||||
return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
|
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
pubkey := k.publicKeyCurve()
|
pubkey := k.publicKeyECDSA()
|
||||||
if pubkey == nil {
|
if pubkey == nil {
|
||||||
return ErrKey
|
return ErrKey
|
||||||
}
|
}
|
||||||
var h hash.Hash
|
|
||||||
switch rr.Algorithm {
|
|
||||||
case ECDSAP256SHA256:
|
|
||||||
h = sha256.New()
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
h = sha512.New384()
|
|
||||||
}
|
|
||||||
io.WriteString(h, string(signeddata))
|
|
||||||
sighash := h.Sum(nil)
|
|
||||||
// Split sigbuf into the r and s coordinates
|
// Split sigbuf into the r and s coordinates
|
||||||
r := big.NewInt(0)
|
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
|
||||||
r.SetBytes(sigbuf[:len(sigbuf)/2])
|
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
|
||||||
s := big.NewInt(0)
|
|
||||||
s.SetBytes(sigbuf[len(sigbuf)/2:])
|
h := hash.New()
|
||||||
if ecdsa.Verify(pubkey, sighash, r, s) {
|
h.Write(signeddata)
|
||||||
|
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ErrSig
|
return ErrSig
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrAlg
|
||||||
}
|
}
|
||||||
// Unknown alg
|
|
||||||
return ErrAlg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidityPeriod uses RFC1982 serial arithmetic to calculate
|
// ValidityPeriod uses RFC1982 serial arithmetic to calculate
|
||||||
// if a signature period is valid. If t is the zero time, the
|
// if a signature period is valid. If t is the zero time, the
|
||||||
// current time is taken other t is.
|
// current time is taken other t is. Returns true if the signature
|
||||||
|
// is valid at the given time, otherwise returns false.
|
||||||
func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
|
func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
|
||||||
var utc int64
|
var utc int64
|
||||||
if t.IsZero() {
|
if t.IsZero() {
|
||||||
@@ -450,39 +482,14 @@ func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the signatures base64 encodedig sigdata as a byte slice.
|
// Return the signatures base64 encodedig sigdata as a byte slice.
|
||||||
func (s *RRSIG) sigBuf() []byte {
|
func (rr *RRSIG) sigBuf() []byte {
|
||||||
sigbuf, err := fromBase64([]byte(s.Signature))
|
sigbuf, err := fromBase64([]byte(rr.Signature))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return sigbuf
|
return sigbuf
|
||||||
}
|
}
|
||||||
|
|
||||||
// setPublicKeyInPrivate sets the public key in the private key.
|
|
||||||
func (k *DNSKEY) setPublicKeyInPrivate(p PrivateKey) bool {
|
|
||||||
switch t := p.(type) {
|
|
||||||
case *dsa.PrivateKey:
|
|
||||||
x := k.publicKeyDSA()
|
|
||||||
if x == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t.PublicKey = *x
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
x := k.publicKeyRSA()
|
|
||||||
if x == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t.PublicKey = *x
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
x := k.publicKeyCurve()
|
|
||||||
if x == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t.PublicKey = *x
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// publicKeyRSA returns the RSA public key from a DNSKEY record.
|
// publicKeyRSA returns the RSA public key from a DNSKEY record.
|
||||||
func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
||||||
keybuf, err := fromBase64([]byte(k.PublicKey))
|
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||||||
@@ -521,8 +528,8 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
|||||||
return pubkey
|
return pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
// publicKeyCurve returns the Curve public key from the DNSKEY record.
|
// publicKeyECDSA returns the Curve public key from the DNSKEY record.
|
||||||
func (k *DNSKEY) publicKeyCurve() *ecdsa.PublicKey {
|
func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
|
||||||
keybuf, err := fromBase64([]byte(k.PublicKey))
|
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -573,81 +580,6 @@ func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
|
|||||||
return pubkey
|
return pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the public key (the value E and N)
|
|
||||||
func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
|
|
||||||
if _E == 0 || _N == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
buf := exponentToBuf(_E)
|
|
||||||
buf = append(buf, _N.Bytes()...)
|
|
||||||
k.PublicKey = toBase64(buf)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the public key for Elliptic Curves
|
|
||||||
func (k *DNSKEY) setPublicKeyCurve(_X, _Y *big.Int) bool {
|
|
||||||
if _X == nil || _Y == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
var intlen int
|
|
||||||
switch k.Algorithm {
|
|
||||||
case ECDSAP256SHA256:
|
|
||||||
intlen = 32
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
intlen = 48
|
|
||||||
}
|
|
||||||
k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the public key for DSA
|
|
||||||
func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
|
|
||||||
if _Q == nil || _P == nil || _G == nil || _Y == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
buf := dsaToBuf(_Q, _P, _G, _Y)
|
|
||||||
k.PublicKey = toBase64(buf)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the public key (the values E and N) for RSA
|
|
||||||
// RFC 3110: Section 2. RSA Public KEY Resource Records
|
|
||||||
func exponentToBuf(_E int) []byte {
|
|
||||||
var buf []byte
|
|
||||||
i := big.NewInt(int64(_E))
|
|
||||||
if len(i.Bytes()) < 256 {
|
|
||||||
buf = make([]byte, 1)
|
|
||||||
buf[0] = uint8(len(i.Bytes()))
|
|
||||||
} else {
|
|
||||||
buf = make([]byte, 3)
|
|
||||||
buf[0] = 0
|
|
||||||
buf[1] = uint8(len(i.Bytes()) >> 8)
|
|
||||||
buf[2] = uint8(len(i.Bytes()))
|
|
||||||
}
|
|
||||||
buf = append(buf, i.Bytes()...)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the public key for X and Y for Curve. The two
|
|
||||||
// values are just concatenated.
|
|
||||||
func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
|
|
||||||
buf := intToBytes(_X, intlen)
|
|
||||||
buf = append(buf, intToBytes(_Y, intlen)...)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the public key for X and Y for Curve. The two
|
|
||||||
// values are just concatenated.
|
|
||||||
func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
|
|
||||||
t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
|
|
||||||
buf := []byte{byte(t)}
|
|
||||||
buf = append(buf, intToBytes(_Q, 20)...)
|
|
||||||
buf = append(buf, intToBytes(_P, 64+t*8)...)
|
|
||||||
buf = append(buf, intToBytes(_G, 64+t*8)...)
|
|
||||||
buf = append(buf, intToBytes(_Y, 64+t*8)...)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
type wireSlice [][]byte
|
type wireSlice [][]byte
|
||||||
|
|
||||||
func (p wireSlice) Len() int { return len(p) }
|
func (p wireSlice) Len() int { return len(p) }
|
||||||
@@ -676,6 +608,12 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
|||||||
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
|
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
|
||||||
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
|
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
|
||||||
// SRV, DNAME, A6
|
// SRV, DNAME, A6
|
||||||
|
//
|
||||||
|
// RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
|
||||||
|
// Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
|
||||||
|
// that needs conversion to lowercase, and twice at that. Since HINFO
|
||||||
|
// records contain no domain names, they are not subject to case
|
||||||
|
// conversion.
|
||||||
switch x := r1.(type) {
|
switch x := r1.(type) {
|
||||||
case *NS:
|
case *NS:
|
||||||
x.Ns = strings.ToLower(x.Ns)
|
x.Ns = strings.ToLower(x.Ns)
|
||||||
@@ -716,41 +654,11 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
|||||||
wires[i] = wire
|
wires[i] = wire
|
||||||
}
|
}
|
||||||
sort.Sort(wires)
|
sort.Sort(wires)
|
||||||
for _, wire := range wires {
|
for i, wire := range wires {
|
||||||
|
if i > 0 && bytes.Equal(wire, wires[i-1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
buf = append(buf, wire...)
|
buf = append(buf, wire...)
|
||||||
}
|
}
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map for algorithm names.
|
|
||||||
var AlgorithmToString = map[uint8]string{
|
|
||||||
RSAMD5: "RSAMD5",
|
|
||||||
DH: "DH",
|
|
||||||
DSA: "DSA",
|
|
||||||
RSASHA1: "RSASHA1",
|
|
||||||
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
|
|
||||||
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
|
|
||||||
RSASHA256: "RSASHA256",
|
|
||||||
RSASHA512: "RSASHA512",
|
|
||||||
ECCGOST: "ECC-GOST",
|
|
||||||
ECDSAP256SHA256: "ECDSAP256SHA256",
|
|
||||||
ECDSAP384SHA384: "ECDSAP384SHA384",
|
|
||||||
INDIRECT: "INDIRECT",
|
|
||||||
PRIVATEDNS: "PRIVATEDNS",
|
|
||||||
PRIVATEOID: "PRIVATEOID",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map of algorithm strings.
|
|
||||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
|
||||||
|
|
||||||
// Map for hash names.
|
|
||||||
var HashToString = map[uint8]string{
|
|
||||||
SHA1: "SHA1",
|
|
||||||
SHA256: "SHA256",
|
|
||||||
GOST94: "GOST94",
|
|
||||||
SHA384: "SHA384",
|
|
||||||
SHA512: "SHA512",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map of hash strings.
|
|
||||||
var StringToHash = reverseInt8(HashToString)
|
|
||||||
|
|||||||
156
vendor/github.com/miekg/dns/dnssec_keygen.go
generated
vendored
Normal file
156
vendor/github.com/miekg/dns/dnssec_keygen.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/dsa"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate generates a DNSKEY of the given bit size.
|
||||||
|
// The public part is put inside the DNSKEY record.
|
||||||
|
// The Algorithm in the key must be set as this will define
|
||||||
|
// what kind of DNSKEY will be generated.
|
||||||
|
// The ECDSA algorithms imply a fixed keysize, in that case
|
||||||
|
// bits should be set to the size of the algorithm.
|
||||||
|
func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
|
||||||
|
switch k.Algorithm {
|
||||||
|
case DSA, DSANSEC3SHA1:
|
||||||
|
if bits != 1024 {
|
||||||
|
return nil, ErrKeySize
|
||||||
|
}
|
||||||
|
case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
|
||||||
|
if bits < 512 || bits > 4096 {
|
||||||
|
return nil, ErrKeySize
|
||||||
|
}
|
||||||
|
case RSASHA512:
|
||||||
|
if bits < 1024 || bits > 4096 {
|
||||||
|
return nil, ErrKeySize
|
||||||
|
}
|
||||||
|
case ECDSAP256SHA256:
|
||||||
|
if bits != 256 {
|
||||||
|
return nil, ErrKeySize
|
||||||
|
}
|
||||||
|
case ECDSAP384SHA384:
|
||||||
|
if bits != 384 {
|
||||||
|
return nil, ErrKeySize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k.Algorithm {
|
||||||
|
case DSA, DSANSEC3SHA1:
|
||||||
|
params := new(dsa.Parameters)
|
||||||
|
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
priv := new(dsa.PrivateKey)
|
||||||
|
priv.PublicKey.Parameters = *params
|
||||||
|
err := dsa.GenerateKey(priv, rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
|
||||||
|
return priv, nil
|
||||||
|
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
|
||||||
|
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
|
||||||
|
return priv, nil
|
||||||
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
|
var c elliptic.Curve
|
||||||
|
switch k.Algorithm {
|
||||||
|
case ECDSAP256SHA256:
|
||||||
|
c = elliptic.P256()
|
||||||
|
case ECDSAP384SHA384:
|
||||||
|
c = elliptic.P384()
|
||||||
|
}
|
||||||
|
priv, err := ecdsa.GenerateKey(c, rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
|
||||||
|
return priv, nil
|
||||||
|
default:
|
||||||
|
return nil, ErrAlg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public key (the value E and N)
|
||||||
|
func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
|
||||||
|
if _E == 0 || _N == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
buf := exponentToBuf(_E)
|
||||||
|
buf = append(buf, _N.Bytes()...)
|
||||||
|
k.PublicKey = toBase64(buf)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public key for Elliptic Curves
|
||||||
|
func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
|
||||||
|
if _X == nil || _Y == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var intlen int
|
||||||
|
switch k.Algorithm {
|
||||||
|
case ECDSAP256SHA256:
|
||||||
|
intlen = 32
|
||||||
|
case ECDSAP384SHA384:
|
||||||
|
intlen = 48
|
||||||
|
}
|
||||||
|
k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public key for DSA
|
||||||
|
func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
|
||||||
|
if _Q == nil || _P == nil || _G == nil || _Y == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
buf := dsaToBuf(_Q, _P, _G, _Y)
|
||||||
|
k.PublicKey = toBase64(buf)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public key (the values E and N) for RSA
|
||||||
|
// RFC 3110: Section 2. RSA Public KEY Resource Records
|
||||||
|
func exponentToBuf(_E int) []byte {
|
||||||
|
var buf []byte
|
||||||
|
i := big.NewInt(int64(_E))
|
||||||
|
if len(i.Bytes()) < 256 {
|
||||||
|
buf = make([]byte, 1)
|
||||||
|
buf[0] = uint8(len(i.Bytes()))
|
||||||
|
} else {
|
||||||
|
buf = make([]byte, 3)
|
||||||
|
buf[0] = 0
|
||||||
|
buf[1] = uint8(len(i.Bytes()) >> 8)
|
||||||
|
buf[2] = uint8(len(i.Bytes()))
|
||||||
|
}
|
||||||
|
buf = append(buf, i.Bytes()...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public key for X and Y for Curve. The two
|
||||||
|
// values are just concatenated.
|
||||||
|
func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
|
||||||
|
buf := intToBytes(_X, intlen)
|
||||||
|
buf = append(buf, intToBytes(_Y, intlen)...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public key for X and Y for Curve. The two
|
||||||
|
// values are just concatenated.
|
||||||
|
func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
|
||||||
|
t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
|
||||||
|
buf := []byte{byte(t)}
|
||||||
|
buf = append(buf, intToBytes(_Q, 20)...)
|
||||||
|
buf = append(buf, intToBytes(_P, 64+t*8)...)
|
||||||
|
buf = append(buf, intToBytes(_G, 64+t*8)...)
|
||||||
|
buf = append(buf, intToBytes(_Y, 64+t*8)...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
133
vendor/github.com/miekg/dns/kscan.go → vendor/github.com/miekg/dns/dnssec_keyscan.go
generated
vendored
133
vendor/github.com/miekg/dns/kscan.go → vendor/github.com/miekg/dns/dnssec_keyscan.go
generated
vendored
@@ -1,15 +1,19 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
|
// NewPrivateKey returns a PrivateKey by parsing the string s.
|
||||||
|
// s should be in the same form of the BIND private key files.
|
||||||
|
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
|
||||||
if s[len(s)-1] != '\n' { // We need a closing newline
|
if s[len(s)-1] != '\n' { // We need a closing newline
|
||||||
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
|
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
|
||||||
}
|
}
|
||||||
@@ -18,9 +22,9 @@ func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
|
|||||||
|
|
||||||
// ReadPrivateKey reads a private key from the io.Reader q. The string file is
|
// ReadPrivateKey reads a private key from the io.Reader q. The string file is
|
||||||
// only used in error reporting.
|
// only used in error reporting.
|
||||||
// The public key must be
|
// The public key must be known, because some cryptographic algorithms embed
|
||||||
// known, because some cryptographic algorithms embed the public inside the privatekey.
|
// the public inside the privatekey.
|
||||||
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
|
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
|
||||||
m, e := parseKey(q, file)
|
m, e := parseKey(q, file)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return nil, e
|
return nil, e
|
||||||
@@ -32,57 +36,63 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
|
|||||||
return nil, ErrPrivKey
|
return nil, ErrPrivKey
|
||||||
}
|
}
|
||||||
// TODO(mg): check if the pubkey matches the private key
|
// TODO(mg): check if the pubkey matches the private key
|
||||||
switch m["algorithm"] {
|
algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0])
|
||||||
case "3 (DSA)":
|
if err != nil {
|
||||||
p, e := readPrivateKeyDSA(m)
|
return nil, ErrPrivKey
|
||||||
if e != nil {
|
}
|
||||||
return nil, e
|
switch uint8(algo) {
|
||||||
}
|
case DSA:
|
||||||
if !k.setPublicKeyInPrivate(p) {
|
priv, e := readPrivateKeyDSA(m)
|
||||||
return nil, ErrKey
|
if e != nil {
|
||||||
}
|
return nil, e
|
||||||
return p, e
|
}
|
||||||
case "1 (RSAMD5)":
|
pub := k.publicKeyDSA()
|
||||||
fallthrough
|
if pub == nil {
|
||||||
case "5 (RSASHA1)":
|
return nil, ErrKey
|
||||||
fallthrough
|
}
|
||||||
case "7 (RSASHA1NSEC3SHA1)":
|
priv.PublicKey = *pub
|
||||||
fallthrough
|
return priv, e
|
||||||
case "8 (RSASHA256)":
|
case RSAMD5:
|
||||||
fallthrough
|
fallthrough
|
||||||
case "10 (RSASHA512)":
|
case RSASHA1:
|
||||||
p, e := readPrivateKeyRSA(m)
|
fallthrough
|
||||||
if e != nil {
|
case RSASHA1NSEC3SHA1:
|
||||||
return nil, e
|
fallthrough
|
||||||
}
|
case RSASHA256:
|
||||||
if !k.setPublicKeyInPrivate(p) {
|
fallthrough
|
||||||
return nil, ErrKey
|
case RSASHA512:
|
||||||
}
|
priv, e := readPrivateKeyRSA(m)
|
||||||
return p, e
|
if e != nil {
|
||||||
case "12 (ECC-GOST)":
|
return nil, e
|
||||||
p, e := readPrivateKeyGOST(m)
|
}
|
||||||
if e != nil {
|
pub := k.publicKeyRSA()
|
||||||
return nil, e
|
if pub == nil {
|
||||||
}
|
return nil, ErrKey
|
||||||
// setPublicKeyInPrivate(p)
|
}
|
||||||
return p, e
|
priv.PublicKey = *pub
|
||||||
case "13 (ECDSAP256SHA256)":
|
return priv, e
|
||||||
fallthrough
|
case ECCGOST:
|
||||||
case "14 (ECDSAP384SHA384)":
|
return nil, ErrPrivKey
|
||||||
p, e := readPrivateKeyECDSA(m)
|
case ECDSAP256SHA256:
|
||||||
if e != nil {
|
fallthrough
|
||||||
return nil, e
|
case ECDSAP384SHA384:
|
||||||
}
|
priv, e := readPrivateKeyECDSA(m)
|
||||||
if !k.setPublicKeyInPrivate(p) {
|
if e != nil {
|
||||||
return nil, ErrKey
|
return nil, e
|
||||||
}
|
}
|
||||||
return p, e
|
pub := k.publicKeyECDSA()
|
||||||
|
if pub == nil {
|
||||||
|
return nil, ErrKey
|
||||||
|
}
|
||||||
|
priv.PublicKey = *pub
|
||||||
|
return priv, e
|
||||||
|
default:
|
||||||
|
return nil, ErrPrivKey
|
||||||
}
|
}
|
||||||
return nil, ErrPrivKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a private key (file) string and create a public key. Return the private key.
|
// Read a private key (file) string and create a public key. Return the private key.
|
||||||
func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) {
|
func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
|
||||||
p := new(rsa.PrivateKey)
|
p := new(rsa.PrivateKey)
|
||||||
p.Primes = []*big.Int{nil, nil}
|
p.Primes = []*big.Int{nil, nil}
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
@@ -119,7 +129,7 @@ func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPrivateKeyDSA(m map[string]string) (PrivateKey, error) {
|
func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
|
||||||
p := new(dsa.PrivateKey)
|
p := new(dsa.PrivateKey)
|
||||||
p.X = big.NewInt(0)
|
p.X = big.NewInt(0)
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
@@ -137,7 +147,7 @@ func readPrivateKeyDSA(m map[string]string) (PrivateKey, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) {
|
func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
|
||||||
p := new(ecdsa.PrivateKey)
|
p := new(ecdsa.PrivateKey)
|
||||||
p.D = big.NewInt(0)
|
p.D = big.NewInt(0)
|
||||||
// TODO: validate that the required flags are present
|
// TODO: validate that the required flags are present
|
||||||
@@ -156,11 +166,6 @@ func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPrivateKeyGOST(m map[string]string) (PrivateKey, error) {
|
|
||||||
// TODO(miek)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseKey reads a private key from r. It returns a map[string]string,
|
// parseKey reads a private key from r. It returns a map[string]string,
|
||||||
// with the key-value pairs, or an error when the file is not correct.
|
// with the key-value pairs, or an error when the file is not correct.
|
||||||
func parseKey(r io.Reader, file string) (map[string]string, error) {
|
func parseKey(r io.Reader, file string) (map[string]string, error) {
|
||||||
@@ -173,9 +178,9 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
|
|||||||
for l := range c {
|
for l := range c {
|
||||||
// It should alternate
|
// It should alternate
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _KEY:
|
case zKey:
|
||||||
k = l.token
|
k = l.token
|
||||||
case _VALUE:
|
case zValue:
|
||||||
if k == "" {
|
if k == "" {
|
||||||
return nil, &ParseError{file, "no private key seen", l}
|
return nil, &ParseError{file, "no private key seen", l}
|
||||||
}
|
}
|
||||||
@@ -205,14 +210,14 @@ func klexer(s *scan, c chan lex) {
|
|||||||
}
|
}
|
||||||
l.token = str
|
l.token = str
|
||||||
if key {
|
if key {
|
||||||
l.value = _KEY
|
l.value = zKey
|
||||||
c <- l
|
c <- l
|
||||||
// Next token is a space, eat it
|
// Next token is a space, eat it
|
||||||
s.tokenText()
|
s.tokenText()
|
||||||
key = false
|
key = false
|
||||||
str = ""
|
str = ""
|
||||||
} else {
|
} else {
|
||||||
l.value = _VALUE
|
l.value = zValue
|
||||||
}
|
}
|
||||||
case ';':
|
case ';':
|
||||||
commt = true
|
commt = true
|
||||||
@@ -221,7 +226,7 @@ func klexer(s *scan, c chan lex) {
|
|||||||
// Reset a comment
|
// Reset a comment
|
||||||
commt = false
|
commt = false
|
||||||
}
|
}
|
||||||
l.value = _VALUE
|
l.value = zValue
|
||||||
l.token = str
|
l.token = str
|
||||||
c <- l
|
c <- l
|
||||||
str = ""
|
str = ""
|
||||||
@@ -238,7 +243,7 @@ func klexer(s *scan, c chan lex) {
|
|||||||
if len(str) > 0 {
|
if len(str) > 0 {
|
||||||
// Send remainder
|
// Send remainder
|
||||||
l.token = str
|
l.token = str
|
||||||
l.value = _VALUE
|
l.value = zValue
|
||||||
c <- l
|
c <- l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
85
vendor/github.com/miekg/dns/dnssec_privkey.go
generated
vendored
Normal file
85
vendor/github.com/miekg/dns/dnssec_privkey.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/dsa"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const format = "Private-key-format: v1.3\n"
|
||||||
|
|
||||||
|
// PrivateKeyString converts a PrivateKey to a string. This string has the same
|
||||||
|
// format as the private-key-file of BIND9 (Private-key-format: v1.3).
|
||||||
|
// It needs some info from the key (the algorithm), so its a method of the DNSKEY
|
||||||
|
// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey
|
||||||
|
func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
|
||||||
|
algorithm := strconv.Itoa(int(r.Algorithm))
|
||||||
|
algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
|
||||||
|
|
||||||
|
switch p := p.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
modulus := toBase64(p.PublicKey.N.Bytes())
|
||||||
|
e := big.NewInt(int64(p.PublicKey.E))
|
||||||
|
publicExponent := toBase64(e.Bytes())
|
||||||
|
privateExponent := toBase64(p.D.Bytes())
|
||||||
|
prime1 := toBase64(p.Primes[0].Bytes())
|
||||||
|
prime2 := toBase64(p.Primes[1].Bytes())
|
||||||
|
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
|
||||||
|
// and from: http://code.google.com/p/go/issues/detail?id=987
|
||||||
|
one := big.NewInt(1)
|
||||||
|
p1 := big.NewInt(0).Sub(p.Primes[0], one)
|
||||||
|
q1 := big.NewInt(0).Sub(p.Primes[1], one)
|
||||||
|
exp1 := big.NewInt(0).Mod(p.D, p1)
|
||||||
|
exp2 := big.NewInt(0).Mod(p.D, q1)
|
||||||
|
coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
|
||||||
|
|
||||||
|
exponent1 := toBase64(exp1.Bytes())
|
||||||
|
exponent2 := toBase64(exp2.Bytes())
|
||||||
|
coefficient := toBase64(coeff.Bytes())
|
||||||
|
|
||||||
|
return format +
|
||||||
|
"Algorithm: " + algorithm + "\n" +
|
||||||
|
"Modulus: " + modulus + "\n" +
|
||||||
|
"PublicExponent: " + publicExponent + "\n" +
|
||||||
|
"PrivateExponent: " + privateExponent + "\n" +
|
||||||
|
"Prime1: " + prime1 + "\n" +
|
||||||
|
"Prime2: " + prime2 + "\n" +
|
||||||
|
"Exponent1: " + exponent1 + "\n" +
|
||||||
|
"Exponent2: " + exponent2 + "\n" +
|
||||||
|
"Coefficient: " + coefficient + "\n"
|
||||||
|
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
var intlen int
|
||||||
|
switch r.Algorithm {
|
||||||
|
case ECDSAP256SHA256:
|
||||||
|
intlen = 32
|
||||||
|
case ECDSAP384SHA384:
|
||||||
|
intlen = 48
|
||||||
|
}
|
||||||
|
private := toBase64(intToBytes(p.D, intlen))
|
||||||
|
return format +
|
||||||
|
"Algorithm: " + algorithm + "\n" +
|
||||||
|
"PrivateKey: " + private + "\n"
|
||||||
|
|
||||||
|
case *dsa.PrivateKey:
|
||||||
|
T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
|
||||||
|
prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
|
||||||
|
subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
|
||||||
|
base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
|
||||||
|
priv := toBase64(intToBytes(p.X, 20))
|
||||||
|
pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
|
||||||
|
return format +
|
||||||
|
"Algorithm: " + algorithm + "\n" +
|
||||||
|
"Prime(p): " + prime + "\n" +
|
||||||
|
"Subprime(q): " + subprime + "\n" +
|
||||||
|
"Base(g): " + base + "\n" +
|
||||||
|
"Private_value(x): " + priv + "\n" +
|
||||||
|
"Public_value(y): " + pub + "\n"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
251
vendor/github.com/miekg/dns/doc.go
generated
vendored
Normal file
251
vendor/github.com/miekg/dns/doc.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
Package dns implements a full featured interface to the Domain Name System.
|
||||||
|
Server- and client-side programming is supported.
|
||||||
|
The package allows complete control over what is send out to the DNS. The package
|
||||||
|
API follows the less-is-more principle, by presenting a small, clean interface.
|
||||||
|
|
||||||
|
The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
|
||||||
|
TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
|
||||||
|
Note that domain names MUST be fully qualified, before sending them, unqualified
|
||||||
|
names in a message will result in a packing failure.
|
||||||
|
|
||||||
|
Resource records are native types. They are not stored in wire format.
|
||||||
|
Basic usage pattern for creating a new resource record:
|
||||||
|
|
||||||
|
r := new(dns.MX)
|
||||||
|
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
|
||||||
|
Class: dns.ClassINET, Ttl: 3600}
|
||||||
|
r.Preference = 10
|
||||||
|
r.Mx = "mx.miek.nl."
|
||||||
|
|
||||||
|
Or directly from a string:
|
||||||
|
|
||||||
|
mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
|
||||||
|
|
||||||
|
Or when the default TTL (3600) and class (IN) suit you:
|
||||||
|
|
||||||
|
mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
|
||||||
|
|
||||||
|
Or even:
|
||||||
|
|
||||||
|
mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
|
||||||
|
|
||||||
|
In the DNS messages are exchanged, these messages contain resource
|
||||||
|
records (sets). Use pattern for creating a message:
|
||||||
|
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("miek.nl.", dns.TypeMX)
|
||||||
|
|
||||||
|
Or when not certain if the domain name is fully qualified:
|
||||||
|
|
||||||
|
m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
|
||||||
|
|
||||||
|
The message m is now a message with the question section set to ask
|
||||||
|
the MX records for the miek.nl. zone.
|
||||||
|
|
||||||
|
The following is slightly more verbose, but more flexible:
|
||||||
|
|
||||||
|
m1 := new(dns.Msg)
|
||||||
|
m1.Id = dns.Id()
|
||||||
|
m1.RecursionDesired = true
|
||||||
|
m1.Question = make([]dns.Question, 1)
|
||||||
|
m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
|
||||||
|
|
||||||
|
After creating a message it can be send.
|
||||||
|
Basic use pattern for synchronous querying the DNS at a
|
||||||
|
server configured on 127.0.0.1 and port 53:
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
|
||||||
|
|
||||||
|
Suppressing multiple outstanding queries (with the same question, type and
|
||||||
|
class) is as easy as setting:
|
||||||
|
|
||||||
|
c.SingleInflight = true
|
||||||
|
|
||||||
|
If these "advanced" features are not needed, a simple UDP query can be send,
|
||||||
|
with:
|
||||||
|
|
||||||
|
in, err := dns.Exchange(m1, "127.0.0.1:53")
|
||||||
|
|
||||||
|
When this functions returns you will get dns message. A dns message consists
|
||||||
|
out of four sections.
|
||||||
|
The question section: in.Question, the answer section: in.Answer,
|
||||||
|
the authority section: in.Ns and the additional section: in.Extra.
|
||||||
|
|
||||||
|
Each of these sections (except the Question section) contain a []RR. Basic
|
||||||
|
use pattern for accessing the rdata of a TXT RR as the first RR in
|
||||||
|
the Answer section:
|
||||||
|
|
||||||
|
if t, ok := in.Answer[0].(*dns.TXT); ok {
|
||||||
|
// do something with t.Txt
|
||||||
|
}
|
||||||
|
|
||||||
|
Domain Name and TXT Character String Representations
|
||||||
|
|
||||||
|
Both domain names and TXT character strings are converted to presentation
|
||||||
|
form both when unpacked and when converted to strings.
|
||||||
|
|
||||||
|
For TXT character strings, tabs, carriage returns and line feeds will be
|
||||||
|
converted to \t, \r and \n respectively. Back slashes and quotations marks
|
||||||
|
will be escaped. Bytes below 32 and above 127 will be converted to \DDD
|
||||||
|
form.
|
||||||
|
|
||||||
|
For domain names, in addition to the above rules brackets, periods,
|
||||||
|
spaces, semicolons and the at symbol are escaped.
|
||||||
|
|
||||||
|
DNSSEC
|
||||||
|
|
||||||
|
DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
|
||||||
|
uses public key cryptography to sign resource records. The
|
||||||
|
public keys are stored in DNSKEY records and the signatures in RRSIG records.
|
||||||
|
|
||||||
|
Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
|
||||||
|
to a request.
|
||||||
|
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetEdns0(4096, true)
|
||||||
|
|
||||||
|
Signature generation, signature verification and key generation are all supported.
|
||||||
|
|
||||||
|
DYNAMIC UPDATES
|
||||||
|
|
||||||
|
Dynamic updates reuses the DNS message format, but renames three of
|
||||||
|
the sections. Question is Zone, Answer is Prerequisite, Authority is
|
||||||
|
Update, only the Additional is not renamed. See RFC 2136 for the gory details.
|
||||||
|
|
||||||
|
You can set a rather complex set of rules for the existence of absence of
|
||||||
|
certain resource records or names in a zone to specify if resource records
|
||||||
|
should be added or removed. The table from RFC 2136 supplemented with the Go
|
||||||
|
DNS function shows which functions exist to specify the prerequisites.
|
||||||
|
|
||||||
|
3.2.4 - Table Of Metavalues Used In Prerequisite Section
|
||||||
|
|
||||||
|
CLASS TYPE RDATA Meaning Function
|
||||||
|
--------------------------------------------------------------
|
||||||
|
ANY ANY empty Name is in use dns.NameUsed
|
||||||
|
ANY rrset empty RRset exists (value indep) dns.RRsetUsed
|
||||||
|
NONE ANY empty Name is not in use dns.NameNotUsed
|
||||||
|
NONE rrset empty RRset does not exist dns.RRsetNotUsed
|
||||||
|
zone rrset rr RRset exists (value dep) dns.Used
|
||||||
|
|
||||||
|
The prerequisite section can also be left empty.
|
||||||
|
If you have decided on the prerequisites you can tell what RRs should
|
||||||
|
be added or deleted. The next table shows the options you have and
|
||||||
|
what functions to call.
|
||||||
|
|
||||||
|
3.4.2.6 - Table Of Metavalues Used In Update Section
|
||||||
|
|
||||||
|
CLASS TYPE RDATA Meaning Function
|
||||||
|
---------------------------------------------------------------
|
||||||
|
ANY ANY empty Delete all RRsets from name dns.RemoveName
|
||||||
|
ANY rrset empty Delete an RRset dns.RemoveRRset
|
||||||
|
NONE rrset rr Delete an RR from RRset dns.Remove
|
||||||
|
zone rrset rr Add to an RRset dns.Insert
|
||||||
|
|
||||||
|
TRANSACTION SIGNATURE
|
||||||
|
|
||||||
|
An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
|
||||||
|
The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
|
||||||
|
|
||||||
|
Basic use pattern when querying with a TSIG name "axfr." (note that these key names
|
||||||
|
must be fully qualified - as they are domain names) and the base64 secret
|
||||||
|
"so6ZGir4GPAqINNh9U5c3A==":
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("miek.nl.", dns.TypeMX)
|
||||||
|
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||||
|
...
|
||||||
|
// When sending the TSIG RR is calculated and filled in before sending
|
||||||
|
|
||||||
|
When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
|
||||||
|
TSIG, this is the basic use pattern. In this example we request an AXFR for
|
||||||
|
miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
|
||||||
|
and using the server 176.58.119.54:
|
||||||
|
|
||||||
|
t := new(dns.Transfer)
|
||||||
|
m := new(dns.Msg)
|
||||||
|
t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||||
|
m.SetAxfr("miek.nl.")
|
||||||
|
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||||
|
c, err := t.In(m, "176.58.119.54:53")
|
||||||
|
for r := range c { ... }
|
||||||
|
|
||||||
|
You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
|
||||||
|
If something is not correct an error is returned.
|
||||||
|
|
||||||
|
Basic use pattern validating and replying to a message that has TSIG set.
|
||||||
|
|
||||||
|
server := &dns.Server{Addr: ":53", Net: "udp"}
|
||||||
|
server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||||
|
go server.ListenAndServe()
|
||||||
|
dns.HandleFunc(".", handleRequest)
|
||||||
|
|
||||||
|
func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetReply(r)
|
||||||
|
if r.IsTsig() != nil {
|
||||||
|
if w.TsigStatus() == nil {
|
||||||
|
// *Msg r has an TSIG record and it was validated
|
||||||
|
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||||
|
} else {
|
||||||
|
// *Msg r has an TSIG records and it was not valided
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.WriteMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
PRIVATE RRS
|
||||||
|
|
||||||
|
RFC 6895 sets aside a range of type codes for private use. This range
|
||||||
|
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
|
||||||
|
can be used, before requesting an official type code from IANA.
|
||||||
|
|
||||||
|
see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
EDNS0
|
||||||
|
|
||||||
|
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
|
||||||
|
by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
|
||||||
|
abused.
|
||||||
|
Basic use pattern for creating an (empty) OPT RR:
|
||||||
|
|
||||||
|
o := new(dns.OPT)
|
||||||
|
o.Hdr.Name = "." // MUST be the root zone, per definition.
|
||||||
|
o.Hdr.Rrtype = dns.TypeOPT
|
||||||
|
|
||||||
|
The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
|
||||||
|
interfaces. Currently only a few have been standardized: EDNS0_NSID
|
||||||
|
(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
|
||||||
|
that these options may be combined in an OPT RR.
|
||||||
|
Basic use pattern for a server to check if (and which) options are set:
|
||||||
|
|
||||||
|
// o is a dns.OPT
|
||||||
|
for _, s := range o.Option {
|
||||||
|
switch e := s.(type) {
|
||||||
|
case *dns.EDNS0_NSID:
|
||||||
|
// do stuff with e.Nsid
|
||||||
|
case *dns.EDNS0_SUBNET:
|
||||||
|
// access e.Family, e.Address, etc.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SIG(0)
|
||||||
|
|
||||||
|
From RFC 2931:
|
||||||
|
|
||||||
|
SIG(0) provides protection for DNS transactions and requests ....
|
||||||
|
... protection for glue records, DNS requests, protection for message headers
|
||||||
|
on requests and responses, and protection of the overall integrity of a response.
|
||||||
|
|
||||||
|
It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
|
||||||
|
secret approach in TSIG.
|
||||||
|
Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
|
||||||
|
RSASHA512.
|
||||||
|
|
||||||
|
Signing subsequent messages in multi-message sessions is not implemented.
|
||||||
|
*/
|
||||||
|
package dns
|
||||||
156
vendor/github.com/miekg/dns/edns.go
generated
vendored
156
vendor/github.com/miekg/dns/edns.go
generated
vendored
@@ -1,29 +1,3 @@
|
|||||||
// EDNS0
|
|
||||||
//
|
|
||||||
// EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
|
|
||||||
// by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
|
|
||||||
// abused.
|
|
||||||
// Basic use pattern for creating an (empty) OPT RR:
|
|
||||||
//
|
|
||||||
// o := new(dns.OPT)
|
|
||||||
// o.Hdr.Name = "." // MUST be the root zone, per definition.
|
|
||||||
// o.Hdr.Rrtype = dns.TypeOPT
|
|
||||||
//
|
|
||||||
// The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
|
|
||||||
// interfaces. Currently only a few have been standardized: EDNS0_NSID
|
|
||||||
// (RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
|
|
||||||
// that these options may be combined in an OPT RR.
|
|
||||||
// Basic use pattern for a server to check if (and which) options are set:
|
|
||||||
//
|
|
||||||
// // o is a dns.OPT
|
|
||||||
// for _, s := range o.Option {
|
|
||||||
// switch e := s.(type) {
|
|
||||||
// case *dns.EDNS0_NSID:
|
|
||||||
// // do stuff with e.Nsid
|
|
||||||
// case *dns.EDNS0_SUBNET:
|
|
||||||
// // access e.Family, e.Address, etc.
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -44,18 +18,18 @@ const (
|
|||||||
EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
|
EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
|
||||||
EDNS0EXPIRE = 0x9 // EDNS0 expire
|
EDNS0EXPIRE = 0x9 // EDNS0 expire
|
||||||
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
|
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
|
||||||
|
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
|
||||||
|
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
|
||||||
_DO = 1 << 15 // dnssec ok
|
_DO = 1 << 15 // dnssec ok
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
|
||||||
|
// See RFC 6891.
|
||||||
type OPT struct {
|
type OPT struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
Option []EDNS0 `dns:"opt"`
|
Option []EDNS0 `dns:"opt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *OPT) Header() *RR_Header {
|
|
||||||
return &rr.Hdr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *OPT) String() string {
|
func (rr *OPT) String() string {
|
||||||
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
|
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
|
||||||
if rr.Do() {
|
if rr.Do() {
|
||||||
@@ -92,6 +66,8 @@ func (rr *OPT) String() string {
|
|||||||
s += "\n; DS HASH UNDERSTOOD: " + o.String()
|
s += "\n; DS HASH UNDERSTOOD: " + o.String()
|
||||||
case *EDNS0_N3U:
|
case *EDNS0_N3U:
|
||||||
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
|
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
|
||||||
|
case *EDNS0_LOCAL:
|
||||||
|
s += "\n; LOCAL OPT: " + o.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
@@ -100,16 +76,13 @@ func (rr *OPT) String() string {
|
|||||||
func (rr *OPT) len() int {
|
func (rr *OPT) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
for i := 0; i < len(rr.Option); i++ {
|
for i := 0; i < len(rr.Option); i++ {
|
||||||
|
l += 4 // Account for 2-byte option code and 2-byte option length.
|
||||||
lo, _ := rr.Option[i].pack()
|
lo, _ := rr.Option[i].pack()
|
||||||
l += 2 + len(lo)
|
l += len(lo)
|
||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *OPT) copy() RR {
|
|
||||||
return &OPT{*rr.Hdr.copyHeader(), rr.Option}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the old value -> delete SetVersion?
|
// return the old value -> delete SetVersion?
|
||||||
|
|
||||||
// Version returns the EDNS version used. Only zero is defined.
|
// Version returns the EDNS version used. Only zero is defined.
|
||||||
@@ -195,7 +168,7 @@ func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
|
|||||||
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
|
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
|
||||||
func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
||||||
|
|
||||||
// The subnet EDNS0 option is used to give the remote nameserver
|
// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
|
||||||
// an idea of where the client lives. It can then give back a different
|
// an idea of where the client lives. It can then give back a different
|
||||||
// answer depending on the location or network topology.
|
// answer depending on the location or network topology.
|
||||||
// Basic use pattern for creating an subnet option:
|
// Basic use pattern for creating an subnet option:
|
||||||
@@ -211,6 +184,11 @@ func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
|||||||
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
|
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
|
||||||
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
|
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
|
||||||
// o.Option = append(o.Option, e)
|
// o.Option = append(o.Option, e)
|
||||||
|
//
|
||||||
|
// Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic
|
||||||
|
// for which netmask applies to the address. This code will parse all the
|
||||||
|
// available bits when unpacking (up to optlen). When packing it will apply
|
||||||
|
// SourceNetmask. If you need more advanced logic, patches welcome and good luck.
|
||||||
type EDNS0_SUBNET struct {
|
type EDNS0_SUBNET struct {
|
||||||
Code uint16 // Always EDNS0SUBNET
|
Code uint16 // Always EDNS0SUBNET
|
||||||
Family uint16 // 1 for IP, 2 for IP6
|
Family uint16 // 1 for IP, 2 for IP6
|
||||||
@@ -237,38 +215,22 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
|
|||||||
if e.SourceNetmask > net.IPv4len*8 {
|
if e.SourceNetmask > net.IPv4len*8 {
|
||||||
return nil, errors.New("dns: bad netmask")
|
return nil, errors.New("dns: bad netmask")
|
||||||
}
|
}
|
||||||
ip := make([]byte, net.IPv4len)
|
if len(e.Address.To4()) != net.IPv4len {
|
||||||
a := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
|
return nil, errors.New("dns: bad address")
|
||||||
for i := 0; i < net.IPv4len; i++ {
|
|
||||||
if i+1 > len(e.Address) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ip[i] = a[i]
|
|
||||||
}
|
}
|
||||||
needLength := e.SourceNetmask / 8
|
ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
|
||||||
if e.SourceNetmask%8 > 0 {
|
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
|
||||||
needLength++
|
b = append(b, ip[:needLength]...)
|
||||||
}
|
|
||||||
ip = ip[:needLength]
|
|
||||||
b = append(b, ip...)
|
|
||||||
case 2:
|
case 2:
|
||||||
if e.SourceNetmask > net.IPv6len*8 {
|
if e.SourceNetmask > net.IPv6len*8 {
|
||||||
return nil, errors.New("dns: bad netmask")
|
return nil, errors.New("dns: bad netmask")
|
||||||
}
|
}
|
||||||
ip := make([]byte, net.IPv6len)
|
if len(e.Address) != net.IPv6len {
|
||||||
a := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
|
return nil, errors.New("dns: bad address")
|
||||||
for i := 0; i < net.IPv6len; i++ {
|
|
||||||
if i+1 > len(e.Address) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ip[i] = a[i]
|
|
||||||
}
|
}
|
||||||
needLength := e.SourceNetmask / 8
|
ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
|
||||||
if e.SourceNetmask%8 > 0 {
|
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
|
||||||
needLength++
|
b = append(b, ip[:needLength]...)
|
||||||
}
|
|
||||||
ip = ip[:needLength]
|
|
||||||
b = append(b, ip...)
|
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("dns: bad address family")
|
return nil, errors.New("dns: bad address family")
|
||||||
}
|
}
|
||||||
@@ -276,8 +238,7 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *EDNS0_SUBNET) unpack(b []byte) error {
|
func (e *EDNS0_SUBNET) unpack(b []byte) error {
|
||||||
lb := len(b)
|
if len(b) < 4 {
|
||||||
if lb < 4 {
|
|
||||||
return ErrBuf
|
return ErrBuf
|
||||||
}
|
}
|
||||||
e.Family, _ = unpackUint16(b, 0)
|
e.Family, _ = unpackUint16(b, 0)
|
||||||
@@ -285,25 +246,27 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
|
|||||||
e.SourceScope = b[3]
|
e.SourceScope = b[3]
|
||||||
switch e.Family {
|
switch e.Family {
|
||||||
case 1:
|
case 1:
|
||||||
addr := make([]byte, 4)
|
if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
|
||||||
for i := 0; i < int(e.SourceNetmask/8); i++ {
|
return errors.New("dns: bad netmask")
|
||||||
if i >= len(addr) || 4+i >= len(b) {
|
}
|
||||||
return ErrBuf
|
addr := make([]byte, net.IPv4len)
|
||||||
}
|
for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
|
||||||
addr[i] = b[4+i]
|
addr[i] = b[4+i]
|
||||||
}
|
}
|
||||||
e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
|
e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
|
||||||
case 2:
|
case 2:
|
||||||
addr := make([]byte, 16)
|
if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
|
||||||
for i := 0; i < int(e.SourceNetmask/8); i++ {
|
return errors.New("dns: bad netmask")
|
||||||
if i >= len(addr) || 4+i >= len(b) {
|
}
|
||||||
return ErrBuf
|
addr := make([]byte, net.IPv6len)
|
||||||
}
|
for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
|
||||||
addr[i] = b[4+i]
|
addr[i] = b[4+i]
|
||||||
}
|
}
|
||||||
e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
|
e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
|
||||||
addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
|
addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
|
||||||
addr[11], addr[12], addr[13], addr[14], addr[15]}
|
addr[11], addr[12], addr[13], addr[14], addr[15]}
|
||||||
|
default:
|
||||||
|
return errors.New("dns: bad address family")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -320,7 +283,7 @@ func (e *EDNS0_SUBNET) String() (s string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set
|
// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
|
||||||
// an expiration on an update RR. This is helpful for clients that cannot clean
|
// an expiration on an update RR. This is helpful for clients that cannot clean
|
||||||
// up after themselves. This is a draft RFC and more information can be found at
|
// up after themselves. This is a draft RFC and more information can be found at
|
||||||
// http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
// http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||||
@@ -358,7 +321,7 @@ func (e *EDNS0_UL) unpack(b []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||||
// Implemented for completeness, as the EDNS0 type code is assigned.
|
// Implemented for completeness, as the EDNS0 type code is assigned.
|
||||||
type EDNS0_LLQ struct {
|
type EDNS0_LLQ struct {
|
||||||
Code uint16 // Always EDNS0LLQ
|
Code uint16 // Always EDNS0LLQ
|
||||||
@@ -499,3 +462,44 @@ func (e *EDNS0_EXPIRE) unpack(b []byte) error {
|
|||||||
e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
|
e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The EDNS0_LOCAL option is used for local/experimental purposes. The option
|
||||||
|
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
|
||||||
|
// (RFC6891), although any unassigned code can actually be used. The content of
|
||||||
|
// the option is made available in Data, unaltered.
|
||||||
|
// Basic use pattern for creating a local option:
|
||||||
|
//
|
||||||
|
// o := new(dns.OPT)
|
||||||
|
// o.Hdr.Name = "."
|
||||||
|
// o.Hdr.Rrtype = dns.TypeOPT
|
||||||
|
// e := new(dns.EDNS0_LOCAL)
|
||||||
|
// e.Code = dns.EDNS0LOCALSTART
|
||||||
|
// e.Data = []byte{72, 82, 74}
|
||||||
|
// o.Option = append(o.Option, e)
|
||||||
|
type EDNS0_LOCAL struct {
|
||||||
|
Code uint16
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
|
||||||
|
func (e *EDNS0_LOCAL) String() string {
|
||||||
|
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EDNS0_LOCAL) pack() ([]byte, error) {
|
||||||
|
b := make([]byte, len(e.Data))
|
||||||
|
copied := copy(b, e.Data)
|
||||||
|
if copied != len(e.Data) {
|
||||||
|
return nil, ErrBuf
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EDNS0_LOCAL) unpack(b []byte) error {
|
||||||
|
e.Data = make([]byte, len(b))
|
||||||
|
copied := copy(e.Data, b)
|
||||||
|
if copied != len(b) {
|
||||||
|
return ErrBuf
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
96
vendor/github.com/miekg/dns/format.go
generated
vendored
Normal file
96
vendor/github.com/miekg/dns/format.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NumField returns the number of rdata fields r has.
|
||||||
|
func NumField(r RR) int {
|
||||||
|
return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns the rdata field i as a string. Fields are indexed starting from 1.
|
||||||
|
// RR types that holds slice data, for instance the NSEC type bitmap will return a single
|
||||||
|
// string where the types are concatenated using a space.
|
||||||
|
// Accessing non existing fields will cause a panic.
|
||||||
|
func Field(r RR, i int) string {
|
||||||
|
if i == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
d := reflect.ValueOf(r).Elem().Field(i)
|
||||||
|
switch k := d.Kind(); k {
|
||||||
|
case reflect.String:
|
||||||
|
return d.String()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return strconv.FormatInt(d.Int(), 10)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return strconv.FormatUint(d.Uint(), 10)
|
||||||
|
case reflect.Slice:
|
||||||
|
switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
|
||||||
|
case `dns:"a"`:
|
||||||
|
// TODO(miek): Hmm store this as 16 bytes
|
||||||
|
if d.Len() < net.IPv6len {
|
||||||
|
return net.IPv4(byte(d.Index(0).Uint()),
|
||||||
|
byte(d.Index(1).Uint()),
|
||||||
|
byte(d.Index(2).Uint()),
|
||||||
|
byte(d.Index(3).Uint())).String()
|
||||||
|
}
|
||||||
|
return net.IPv4(byte(d.Index(12).Uint()),
|
||||||
|
byte(d.Index(13).Uint()),
|
||||||
|
byte(d.Index(14).Uint()),
|
||||||
|
byte(d.Index(15).Uint())).String()
|
||||||
|
case `dns:"aaaa"`:
|
||||||
|
return net.IP{
|
||||||
|
byte(d.Index(0).Uint()),
|
||||||
|
byte(d.Index(1).Uint()),
|
||||||
|
byte(d.Index(2).Uint()),
|
||||||
|
byte(d.Index(3).Uint()),
|
||||||
|
byte(d.Index(4).Uint()),
|
||||||
|
byte(d.Index(5).Uint()),
|
||||||
|
byte(d.Index(6).Uint()),
|
||||||
|
byte(d.Index(7).Uint()),
|
||||||
|
byte(d.Index(8).Uint()),
|
||||||
|
byte(d.Index(9).Uint()),
|
||||||
|
byte(d.Index(10).Uint()),
|
||||||
|
byte(d.Index(11).Uint()),
|
||||||
|
byte(d.Index(12).Uint()),
|
||||||
|
byte(d.Index(13).Uint()),
|
||||||
|
byte(d.Index(14).Uint()),
|
||||||
|
byte(d.Index(15).Uint()),
|
||||||
|
}.String()
|
||||||
|
case `dns:"nsec"`:
|
||||||
|
if d.Len() == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s := Type(d.Index(0).Uint()).String()
|
||||||
|
for i := 1; i < d.Len(); i++ {
|
||||||
|
s += " " + Type(d.Index(i).Uint()).String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
case `dns:"wks"`:
|
||||||
|
if d.Len() == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s := strconv.Itoa(int(d.Index(0).Uint()))
|
||||||
|
for i := 0; i < d.Len(); i++ {
|
||||||
|
s += " " + strconv.Itoa(int(d.Index(i).Uint()))
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
default:
|
||||||
|
// if it does not have a tag its a string slice
|
||||||
|
fallthrough
|
||||||
|
case `dns:"txt"`:
|
||||||
|
if d.Len() == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s := d.Index(0).String()
|
||||||
|
for i := 1; i < d.Len(); i++ {
|
||||||
|
s += " " + d.Index(i).String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
157
vendor/github.com/miekg/dns/keygen.go
generated
vendored
157
vendor/github.com/miekg/dns/keygen.go
generated
vendored
@@ -1,157 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/dsa"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"math/big"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const _FORMAT = "Private-key-format: v1.3\n"
|
|
||||||
|
|
||||||
// Empty interface that is used as a wrapper around all possible
|
|
||||||
// private key implementations from the crypto package.
|
|
||||||
type PrivateKey interface{}
|
|
||||||
|
|
||||||
// Generate generates a DNSKEY of the given bit size.
|
|
||||||
// The public part is put inside the DNSKEY record.
|
|
||||||
// The Algorithm in the key must be set as this will define
|
|
||||||
// what kind of DNSKEY will be generated.
|
|
||||||
// The ECDSA algorithms imply a fixed keysize, in that case
|
|
||||||
// bits should be set to the size of the algorithm.
|
|
||||||
func (r *DNSKEY) Generate(bits int) (PrivateKey, error) {
|
|
||||||
switch r.Algorithm {
|
|
||||||
case DSA, DSANSEC3SHA1:
|
|
||||||
if bits != 1024 {
|
|
||||||
return nil, ErrKeySize
|
|
||||||
}
|
|
||||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
|
|
||||||
if bits < 512 || bits > 4096 {
|
|
||||||
return nil, ErrKeySize
|
|
||||||
}
|
|
||||||
case RSASHA512:
|
|
||||||
if bits < 1024 || bits > 4096 {
|
|
||||||
return nil, ErrKeySize
|
|
||||||
}
|
|
||||||
case ECDSAP256SHA256:
|
|
||||||
if bits != 256 {
|
|
||||||
return nil, ErrKeySize
|
|
||||||
}
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
if bits != 384 {
|
|
||||||
return nil, ErrKeySize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.Algorithm {
|
|
||||||
case DSA, DSANSEC3SHA1:
|
|
||||||
params := new(dsa.Parameters)
|
|
||||||
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
priv := new(dsa.PrivateKey)
|
|
||||||
priv.PublicKey.Parameters = *params
|
|
||||||
err := dsa.GenerateKey(priv, rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
|
|
||||||
return priv, nil
|
|
||||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
|
|
||||||
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
|
|
||||||
return priv, nil
|
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
|
||||||
var c elliptic.Curve
|
|
||||||
switch r.Algorithm {
|
|
||||||
case ECDSAP256SHA256:
|
|
||||||
c = elliptic.P256()
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
c = elliptic.P384()
|
|
||||||
}
|
|
||||||
priv, err := ecdsa.GenerateKey(c, rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r.setPublicKeyCurve(priv.PublicKey.X, priv.PublicKey.Y)
|
|
||||||
return priv, nil
|
|
||||||
default:
|
|
||||||
return nil, ErrAlg
|
|
||||||
}
|
|
||||||
return nil, nil // Dummy return
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrivateKeyString converts a PrivateKey to a string. This
|
|
||||||
// string has the same format as the private-key-file of BIND9 (Private-key-format: v1.3).
|
|
||||||
// It needs some info from the key (hashing, keytag), so its a method of the DNSKEY.
|
|
||||||
func (r *DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
|
|
||||||
switch t := p.(type) {
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")"
|
|
||||||
modulus := toBase64(t.PublicKey.N.Bytes())
|
|
||||||
e := big.NewInt(int64(t.PublicKey.E))
|
|
||||||
publicExponent := toBase64(e.Bytes())
|
|
||||||
privateExponent := toBase64(t.D.Bytes())
|
|
||||||
prime1 := toBase64(t.Primes[0].Bytes())
|
|
||||||
prime2 := toBase64(t.Primes[1].Bytes())
|
|
||||||
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
|
|
||||||
// and from: http://code.google.com/p/go/issues/detail?id=987
|
|
||||||
one := big.NewInt(1)
|
|
||||||
minusone := big.NewInt(-1)
|
|
||||||
p_1 := big.NewInt(0).Sub(t.Primes[0], one)
|
|
||||||
q_1 := big.NewInt(0).Sub(t.Primes[1], one)
|
|
||||||
exp1 := big.NewInt(0).Mod(t.D, p_1)
|
|
||||||
exp2 := big.NewInt(0).Mod(t.D, q_1)
|
|
||||||
coeff := big.NewInt(0).Exp(t.Primes[1], minusone, t.Primes[0])
|
|
||||||
|
|
||||||
exponent1 := toBase64(exp1.Bytes())
|
|
||||||
exponent2 := toBase64(exp2.Bytes())
|
|
||||||
coefficient := toBase64(coeff.Bytes())
|
|
||||||
|
|
||||||
s = _FORMAT +
|
|
||||||
"Algorithm: " + algorithm + "\n" +
|
|
||||||
"Modules: " + modulus + "\n" +
|
|
||||||
"PublicExponent: " + publicExponent + "\n" +
|
|
||||||
"PrivateExponent: " + privateExponent + "\n" +
|
|
||||||
"Prime1: " + prime1 + "\n" +
|
|
||||||
"Prime2: " + prime2 + "\n" +
|
|
||||||
"Exponent1: " + exponent1 + "\n" +
|
|
||||||
"Exponent2: " + exponent2 + "\n" +
|
|
||||||
"Coefficient: " + coefficient + "\n"
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")"
|
|
||||||
var intlen int
|
|
||||||
switch r.Algorithm {
|
|
||||||
case ECDSAP256SHA256:
|
|
||||||
intlen = 32
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
intlen = 48
|
|
||||||
}
|
|
||||||
private := toBase64(intToBytes(t.D, intlen))
|
|
||||||
s = _FORMAT +
|
|
||||||
"Algorithm: " + algorithm + "\n" +
|
|
||||||
"PrivateKey: " + private + "\n"
|
|
||||||
case *dsa.PrivateKey:
|
|
||||||
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")"
|
|
||||||
T := divRoundUp(divRoundUp(t.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
|
|
||||||
prime := toBase64(intToBytes(t.PublicKey.Parameters.P, 64+T*8))
|
|
||||||
subprime := toBase64(intToBytes(t.PublicKey.Parameters.Q, 20))
|
|
||||||
base := toBase64(intToBytes(t.PublicKey.Parameters.G, 64+T*8))
|
|
||||||
priv := toBase64(intToBytes(t.X, 20))
|
|
||||||
pub := toBase64(intToBytes(t.PublicKey.Y, 64+T*8))
|
|
||||||
s = _FORMAT +
|
|
||||||
"Algorithm: " + algorithm + "\n" +
|
|
||||||
"Prime(p): " + prime + "\n" +
|
|
||||||
"Subprime(q): " + subprime + "\n" +
|
|
||||||
"Base(g): " + base + "\n" +
|
|
||||||
"Private_value(x): " + priv + "\n" +
|
|
||||||
"Public_value(y): " + pub + "\n"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
12
vendor/github.com/miekg/dns/labels.go
generated
vendored
12
vendor/github.com/miekg/dns/labels.go
generated
vendored
@@ -4,9 +4,11 @@ package dns
|
|||||||
|
|
||||||
// SplitDomainName splits a name string into it's labels.
|
// SplitDomainName splits a name string into it's labels.
|
||||||
// www.miek.nl. returns []string{"www", "miek", "nl"}
|
// www.miek.nl. returns []string{"www", "miek", "nl"}
|
||||||
|
// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
|
||||||
// The root label (.) returns nil. Note that using
|
// The root label (.) returns nil. Note that using
|
||||||
// strings.Split(s) will work in most cases, but does not handle
|
// strings.Split(s) will work in most cases, but does not handle
|
||||||
// escaped dots (\.) for instance.
|
// escaped dots (\.) for instance.
|
||||||
|
// s must be a syntactically valid domain name, see IsDomainName.
|
||||||
func SplitDomainName(s string) (labels []string) {
|
func SplitDomainName(s string) (labels []string) {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -45,6 +47,8 @@ func SplitDomainName(s string) (labels []string) {
|
|||||||
//
|
//
|
||||||
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
|
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
|
||||||
// www.miek.nl. and www.bla.nl. have one label in common: nl
|
// www.miek.nl. and www.bla.nl. have one label in common: nl
|
||||||
|
//
|
||||||
|
// s1 and s2 must be syntactically valid domain names.
|
||||||
func CompareDomainName(s1, s2 string) (n int) {
|
func CompareDomainName(s1, s2 string) (n int) {
|
||||||
s1 = Fqdn(s1)
|
s1 = Fqdn(s1)
|
||||||
s2 = Fqdn(s2)
|
s2 = Fqdn(s2)
|
||||||
@@ -85,6 +89,7 @@ func CompareDomainName(s1, s2 string) (n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountLabel counts the the number of labels in the string s.
|
// CountLabel counts the the number of labels in the string s.
|
||||||
|
// s must be a syntactically valid domain name.
|
||||||
func CountLabel(s string) (labels int) {
|
func CountLabel(s string) (labels int) {
|
||||||
if s == "." {
|
if s == "." {
|
||||||
return
|
return
|
||||||
@@ -98,12 +103,12 @@ func CountLabel(s string) (labels int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split splits a name s into its label indexes.
|
// Split splits a name s into its label indexes.
|
||||||
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
|
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
|
||||||
// The root name (.) returns nil. Also see dns.SplitDomainName.
|
// The root name (.) returns nil. Also see SplitDomainName.
|
||||||
|
// s must be a syntactically valid domain name.
|
||||||
func Split(s string) []int {
|
func Split(s string) []int {
|
||||||
if s == "." {
|
if s == "." {
|
||||||
return nil
|
return nil
|
||||||
@@ -119,12 +124,12 @@ func Split(s string) []int {
|
|||||||
}
|
}
|
||||||
idx = append(idx, off)
|
idx = append(idx, off)
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextLabel returns the index of the start of the next label in the
|
// NextLabel returns the index of the start of the next label in the
|
||||||
// string s starting at offset.
|
// string s starting at offset.
|
||||||
// The bool end is true when the end of the string has been reached.
|
// The bool end is true when the end of the string has been reached.
|
||||||
|
// Also see PrevLabel.
|
||||||
func NextLabel(s string, offset int) (i int, end bool) {
|
func NextLabel(s string, offset int) (i int, end bool) {
|
||||||
quote := false
|
quote := false
|
||||||
for i = offset; i < len(s)-1; i++ {
|
for i = offset; i < len(s)-1; i++ {
|
||||||
@@ -147,6 +152,7 @@ func NextLabel(s string, offset int) (i int, end bool) {
|
|||||||
// PrevLabel returns the index of the label when starting from the right and
|
// PrevLabel returns the index of the label when starting from the right and
|
||||||
// jumping n labels to the left.
|
// jumping n labels to the left.
|
||||||
// The bool start is true when the start of the string has been overshot.
|
// The bool start is true when the start of the string has been overshot.
|
||||||
|
// Also see NextLabel.
|
||||||
func PrevLabel(s string, n int) (i int, start bool) {
|
func PrevLabel(s string, n int) (i int, start bool) {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return len(s), false
|
return len(s), false
|
||||||
|
|||||||
559
vendor/github.com/miekg/dns/msg.go
generated
vendored
559
vendor/github.com/miekg/dns/msg.go
generated
vendored
@@ -23,29 +23,40 @@ import (
|
|||||||
const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrAlg error = &Error{err: "bad algorithm"}
|
// ErrAlg indicates an error with the (DNSSEC) algorithm.
|
||||||
ErrAuth error = &Error{err: "bad authentication"}
|
ErrAlg error = &Error{err: "bad algorithm"}
|
||||||
ErrBuf error = &Error{err: "buffer size too small"}
|
// ErrAuth indicates an error in the TSIG authentication.
|
||||||
ErrConnEmpty error = &Error{err: "conn has no connection"}
|
ErrAuth error = &Error{err: "bad authentication"}
|
||||||
ErrConn error = &Error{err: "conn holds both UDP and TCP connection"}
|
// ErrBuf indicates that the buffer used it too small for the message.
|
||||||
|
ErrBuf error = &Error{err: "buffer size too small"}
|
||||||
|
// ErrConnEmpty indicates a connection is being uses before it is initialized.
|
||||||
|
ErrConnEmpty error = &Error{err: "conn has no connection"}
|
||||||
|
// ErrExtendedRcode ...
|
||||||
ErrExtendedRcode error = &Error{err: "bad extended rcode"}
|
ErrExtendedRcode error = &Error{err: "bad extended rcode"}
|
||||||
ErrFqdn error = &Error{err: "domain must be fully qualified"}
|
// ErrFqdn indicates that a domain name does not have a closing dot.
|
||||||
ErrId error = &Error{err: "id mismatch"}
|
ErrFqdn error = &Error{err: "domain must be fully qualified"}
|
||||||
ErrKeyAlg error = &Error{err: "bad key algorithm"}
|
// ErrId indicates there is a mismatch with the message's ID.
|
||||||
ErrKey error = &Error{err: "bad key"}
|
ErrId error = &Error{err: "id mismatch"}
|
||||||
ErrKeySize error = &Error{err: "bad key size"}
|
// ErrKeyAlg indicates that the algorithm in the key is not valid.
|
||||||
ErrNoSig error = &Error{err: "no signature found"}
|
ErrKeyAlg error = &Error{err: "bad key algorithm"}
|
||||||
ErrPrivKey error = &Error{err: "bad private key"}
|
ErrKey error = &Error{err: "bad key"}
|
||||||
ErrRcode error = &Error{err: "bad rcode"}
|
ErrKeySize error = &Error{err: "bad key size"}
|
||||||
ErrRdata error = &Error{err: "bad rdata"}
|
ErrNoSig error = &Error{err: "no signature found"}
|
||||||
ErrRRset error = &Error{err: "bad rrset"}
|
ErrPrivKey error = &Error{err: "bad private key"}
|
||||||
ErrSecret error = &Error{err: "no secrets defined"}
|
ErrRcode error = &Error{err: "bad rcode"}
|
||||||
ErrServ error = &Error{err: "no servers could be reached"}
|
ErrRdata error = &Error{err: "bad rdata"}
|
||||||
ErrShortRead error = &Error{err: "short read"}
|
ErrRRset error = &Error{err: "bad rrset"}
|
||||||
ErrSig error = &Error{err: "bad signature"}
|
ErrSecret error = &Error{err: "no secrets defined"}
|
||||||
ErrSigGen error = &Error{err: "bad signature generation"}
|
ErrShortRead error = &Error{err: "short read"}
|
||||||
ErrSoa error = &Error{err: "no SOA"}
|
// ErrSig indicates that a signature can not be cryptographically validated.
|
||||||
ErrTime error = &Error{err: "bad time"}
|
ErrSig error = &Error{err: "bad signature"}
|
||||||
|
// ErrSOA indicates that no SOA RR was seen when doing zone transfers.
|
||||||
|
ErrSoa error = &Error{err: "no SOA"}
|
||||||
|
// ErrTime indicates a timing error in TSIG authentication.
|
||||||
|
ErrTime error = &Error{err: "bad time"}
|
||||||
|
// ErrTruncated indicates that we failed to unpack a truncated message.
|
||||||
|
// We unpacked as much as we had so Msg can still be used, if desired.
|
||||||
|
ErrTruncated error = &Error{err: "failed to unpack truncated message"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Id, by default, returns a 16 bits random number to be used as a
|
// Id, by default, returns a 16 bits random number to be used as a
|
||||||
@@ -56,8 +67,7 @@ var (
|
|||||||
// dns.Id = func() uint16 { return 3 }
|
// dns.Id = func() uint16 { return 3 }
|
||||||
var Id func() uint16 = id
|
var Id func() uint16 = id
|
||||||
|
|
||||||
// A manually-unpacked version of (id, bits).
|
// MsgHdr is a a manually-unpacked version of (id, bits).
|
||||||
// This is in its own struct for easy printing.
|
|
||||||
type MsgHdr struct {
|
type MsgHdr struct {
|
||||||
Id uint16
|
Id uint16
|
||||||
Response bool
|
Response bool
|
||||||
@@ -72,7 +82,7 @@ type MsgHdr struct {
|
|||||||
Rcode int
|
Rcode int
|
||||||
}
|
}
|
||||||
|
|
||||||
// The layout of a DNS message.
|
// Msg contains the layout of a DNS message.
|
||||||
type Msg struct {
|
type Msg struct {
|
||||||
MsgHdr
|
MsgHdr
|
||||||
Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format. This not part of the official DNS packet format.
|
Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format. This not part of the official DNS packet format.
|
||||||
@@ -82,87 +92,10 @@ type Msg struct {
|
|||||||
Extra []RR // Holds the RR(s) of the additional section.
|
Extra []RR // Holds the RR(s) of the additional section.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map of strings for each RR wire type.
|
// StringToType is the reverse of TypeToString, needed for string parsing.
|
||||||
var TypeToString = map[uint16]string{
|
|
||||||
TypeA: "A",
|
|
||||||
TypeAAAA: "AAAA",
|
|
||||||
TypeAFSDB: "AFSDB",
|
|
||||||
TypeANY: "ANY", // Meta RR
|
|
||||||
TypeATMA: "ATMA",
|
|
||||||
TypeAXFR: "AXFR", // Meta RR
|
|
||||||
TypeCAA: "CAA",
|
|
||||||
TypeCDNSKEY: "CDNSKEY",
|
|
||||||
TypeCDS: "CDS",
|
|
||||||
TypeCERT: "CERT",
|
|
||||||
TypeCNAME: "CNAME",
|
|
||||||
TypeDHCID: "DHCID",
|
|
||||||
TypeDLV: "DLV",
|
|
||||||
TypeDNAME: "DNAME",
|
|
||||||
TypeDNSKEY: "DNSKEY",
|
|
||||||
TypeDS: "DS",
|
|
||||||
TypeEID: "EID",
|
|
||||||
TypeEUI48: "EUI48",
|
|
||||||
TypeEUI64: "EUI64",
|
|
||||||
TypeGID: "GID",
|
|
||||||
TypeGPOS: "GPOS",
|
|
||||||
TypeHINFO: "HINFO",
|
|
||||||
TypeHIP: "HIP",
|
|
||||||
TypeIPSECKEY: "IPSECKEY",
|
|
||||||
TypeISDN: "ISDN",
|
|
||||||
TypeIXFR: "IXFR", // Meta RR
|
|
||||||
TypeKEY: "KEY",
|
|
||||||
TypeKX: "KX",
|
|
||||||
TypeL32: "L32",
|
|
||||||
TypeL64: "L64",
|
|
||||||
TypeLOC: "LOC",
|
|
||||||
TypeLP: "LP",
|
|
||||||
TypeMB: "MB",
|
|
||||||
TypeMD: "MD",
|
|
||||||
TypeMF: "MF",
|
|
||||||
TypeMG: "MG",
|
|
||||||
TypeMINFO: "MINFO",
|
|
||||||
TypeMR: "MR",
|
|
||||||
TypeMX: "MX",
|
|
||||||
TypeNAPTR: "NAPTR",
|
|
||||||
TypeNID: "NID",
|
|
||||||
TypeNINFO: "NINFO",
|
|
||||||
TypeNIMLOC: "NIMLOC",
|
|
||||||
TypeNS: "NS",
|
|
||||||
TypeNSAP: "NSAP",
|
|
||||||
TypeNSAPPTR: "NSAP-PTR",
|
|
||||||
TypeNSEC3: "NSEC3",
|
|
||||||
TypeNSEC3PARAM: "NSEC3PARAM",
|
|
||||||
TypeNSEC: "NSEC",
|
|
||||||
TypeNULL: "NULL",
|
|
||||||
TypeOPT: "OPT",
|
|
||||||
TypeOPENPGPKEY: "OPENPGPKEY",
|
|
||||||
TypePTR: "PTR",
|
|
||||||
TypeRKEY: "RKEY",
|
|
||||||
TypeRP: "RP",
|
|
||||||
TypeRRSIG: "RRSIG",
|
|
||||||
TypeRT: "RT",
|
|
||||||
TypeSIG: "SIG",
|
|
||||||
TypeSOA: "SOA",
|
|
||||||
TypeSPF: "SPF",
|
|
||||||
TypeSRV: "SRV",
|
|
||||||
TypeSSHFP: "SSHFP",
|
|
||||||
TypeTA: "TA",
|
|
||||||
TypeTALINK: "TALINK",
|
|
||||||
TypeTKEY: "TKEY", // Meta RR
|
|
||||||
TypeTLSA: "TLSA",
|
|
||||||
TypeTSIG: "TSIG", // Meta RR
|
|
||||||
TypeTXT: "TXT",
|
|
||||||
TypePX: "PX",
|
|
||||||
TypeUID: "UID",
|
|
||||||
TypeUINFO: "UINFO",
|
|
||||||
TypeUNSPEC: "UNSPEC",
|
|
||||||
TypeURI: "URI",
|
|
||||||
TypeWKS: "WKS",
|
|
||||||
TypeX25: "X25",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse, needed for string parsing.
|
|
||||||
var StringToType = reverseInt16(TypeToString)
|
var StringToType = reverseInt16(TypeToString)
|
||||||
|
|
||||||
|
// StringToClass is the reverse of ClassToString, needed for string parsing.
|
||||||
var StringToClass = reverseInt16(ClassToString)
|
var StringToClass = reverseInt16(ClassToString)
|
||||||
|
|
||||||
// Map of opcodes strings.
|
// Map of opcodes strings.
|
||||||
@@ -171,7 +104,7 @@ var StringToOpcode = reverseInt(OpcodeToString)
|
|||||||
// Map of rcodes strings.
|
// Map of rcodes strings.
|
||||||
var StringToRcode = reverseInt(RcodeToString)
|
var StringToRcode = reverseInt(RcodeToString)
|
||||||
|
|
||||||
// Map of strings for each CLASS wire type.
|
// ClassToString is a maps Classes to strings for each CLASS wire type.
|
||||||
var ClassToString = map[uint16]string{
|
var ClassToString = map[uint16]string{
|
||||||
ClassINET: "IN",
|
ClassINET: "IN",
|
||||||
ClassCSNET: "CS",
|
ClassCSNET: "CS",
|
||||||
@@ -181,7 +114,7 @@ var ClassToString = map[uint16]string{
|
|||||||
ClassANY: "ANY",
|
ClassANY: "ANY",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map of strings for opcodes.
|
// OpcodeToString maps Opcodes to strings.
|
||||||
var OpcodeToString = map[int]string{
|
var OpcodeToString = map[int]string{
|
||||||
OpcodeQuery: "QUERY",
|
OpcodeQuery: "QUERY",
|
||||||
OpcodeIQuery: "IQUERY",
|
OpcodeIQuery: "IQUERY",
|
||||||
@@ -190,7 +123,7 @@ var OpcodeToString = map[int]string{
|
|||||||
OpcodeUpdate: "UPDATE",
|
OpcodeUpdate: "UPDATE",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map of strings for rcodes.
|
// RcodeToString maps Rcodes to strings.
|
||||||
var RcodeToString = map[int]string{
|
var RcodeToString = map[int]string{
|
||||||
RcodeSuccess: "NOERROR",
|
RcodeSuccess: "NOERROR",
|
||||||
RcodeFormatError: "FORMERR",
|
RcodeFormatError: "FORMERR",
|
||||||
@@ -225,7 +158,7 @@ var RcodeToString = map[int]string{
|
|||||||
// PackDomainName packs a domain name s into msg[off:].
|
// PackDomainName packs a domain name s into msg[off:].
|
||||||
// If compression is wanted compress must be true and the compression
|
// If compression is wanted compress must be true and the compression
|
||||||
// map needs to hold a mapping between domain names and offsets
|
// map needs to hold a mapping between domain names and offsets
|
||||||
// pointing into msg[].
|
// pointing into msg.
|
||||||
func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
||||||
off1, _, err = packDomainName(s, msg, off, compression, compress)
|
off1, _, err = packDomainName(s, msg, off, compression, compress)
|
||||||
return
|
return
|
||||||
@@ -264,7 +197,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
|||||||
// Emit sequence of counted strings, chopping at dots.
|
// Emit sequence of counted strings, chopping at dots.
|
||||||
begin := 0
|
begin := 0
|
||||||
bs := []byte(s)
|
bs := []byte(s)
|
||||||
ro_bs, bs_fresh, escaped_dot := s, true, false
|
roBs, bsFresh, escapedDot := s, true, false
|
||||||
for i := 0; i < ls; i++ {
|
for i := 0; i < ls; i++ {
|
||||||
if bs[i] == '\\' {
|
if bs[i] == '\\' {
|
||||||
for j := i; j < ls-1; j++ {
|
for j := i; j < ls-1; j++ {
|
||||||
@@ -288,13 +221,13 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
|||||||
} else if bs[i] == 'n' {
|
} else if bs[i] == 'n' {
|
||||||
bs[i] = '\n'
|
bs[i] = '\n'
|
||||||
}
|
}
|
||||||
escaped_dot = bs[i] == '.'
|
escapedDot = bs[i] == '.'
|
||||||
bs_fresh = false
|
bsFresh = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if bs[i] == '.' {
|
if bs[i] == '.' {
|
||||||
if i > 0 && bs[i-1] == '.' && !escaped_dot {
|
if i > 0 && bs[i-1] == '.' && !escapedDot {
|
||||||
// two dots back to back is not legal
|
// two dots back to back is not legal
|
||||||
return lenmsg, labels, ErrRdata
|
return lenmsg, labels, ErrRdata
|
||||||
}
|
}
|
||||||
@@ -320,16 +253,16 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
|||||||
}
|
}
|
||||||
off++
|
off++
|
||||||
}
|
}
|
||||||
if compress && !bs_fresh {
|
if compress && !bsFresh {
|
||||||
ro_bs = string(bs)
|
roBs = string(bs)
|
||||||
bs_fresh = true
|
bsFresh = true
|
||||||
}
|
}
|
||||||
// Dont try to compress '.'
|
// Don't try to compress '.'
|
||||||
if compress && ro_bs[begin:] != "." {
|
if compress && roBs[begin:] != "." {
|
||||||
if p, ok := compression[ro_bs[begin:]]; !ok {
|
if p, ok := compression[roBs[begin:]]; !ok {
|
||||||
// Only offsets smaller than this can be used.
|
// Only offsets smaller than this can be used.
|
||||||
if offset < maxCompressionOffset {
|
if offset < maxCompressionOffset {
|
||||||
compression[ro_bs[begin:]] = offset
|
compression[roBs[begin:]] = offset
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The first hit is the longest matching dname
|
// The first hit is the longest matching dname
|
||||||
@@ -348,7 +281,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
|||||||
labels++
|
labels++
|
||||||
begin = i + 1
|
begin = i + 1
|
||||||
}
|
}
|
||||||
escaped_dot = false
|
escapedDot = false
|
||||||
}
|
}
|
||||||
// Root label is special
|
// Root label is special
|
||||||
if len(bs) == 1 && bs[0] == '.' {
|
if len(bs) == 1 && bs[0] == '.' {
|
||||||
@@ -401,9 +334,6 @@ Loop:
|
|||||||
case 0x00:
|
case 0x00:
|
||||||
if c == 0x00 {
|
if c == 0x00 {
|
||||||
// end of name
|
// end of name
|
||||||
if len(s) == 0 {
|
|
||||||
return ".", off, nil
|
|
||||||
}
|
|
||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
// literal string
|
// literal string
|
||||||
@@ -464,6 +394,9 @@ Loop:
|
|||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
off1 = off
|
off1 = off
|
||||||
}
|
}
|
||||||
|
if len(s) == 0 {
|
||||||
|
s = []byte(".")
|
||||||
|
}
|
||||||
return string(s), off1, nil
|
return string(s), off1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,17 +464,46 @@ func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
|
|||||||
return offset, nil
|
return offset, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unpackTxt(msg []byte, offset, rdend int) ([]string, int, error) {
|
func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) {
|
||||||
var err error
|
if offset >= len(msg) {
|
||||||
var ss []string
|
return offset, ErrBuf
|
||||||
|
}
|
||||||
|
bs := tmp[:len(s)]
|
||||||
|
copy(bs, s)
|
||||||
|
for i := 0; i < len(bs); i++ {
|
||||||
|
if len(msg) <= offset {
|
||||||
|
return offset, ErrBuf
|
||||||
|
}
|
||||||
|
if bs[i] == '\\' {
|
||||||
|
i++
|
||||||
|
if i == len(bs) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// check for \DDD
|
||||||
|
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
|
||||||
|
msg[offset] = dddToByte(bs[i:])
|
||||||
|
i += 2
|
||||||
|
} else {
|
||||||
|
msg[offset] = bs[i]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg[offset] = bs[i]
|
||||||
|
}
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
|
||||||
|
off = off0
|
||||||
var s string
|
var s string
|
||||||
for offset < rdend && err == nil {
|
for off < len(msg) && err == nil {
|
||||||
s, offset, err = unpackTxtString(msg, offset)
|
s, off, err = unpackTxtString(msg, off)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ss = append(ss, s)
|
ss = append(ss, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ss, offset, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func unpackTxtString(msg []byte, offset int) (string, int, error) {
|
func unpackTxtString(msg []byte, offset int) (string, int, error) {
|
||||||
@@ -652,6 +614,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||||||
off += len(b)
|
off += len(b)
|
||||||
}
|
}
|
||||||
case `dns:"a"`:
|
case `dns:"a"`:
|
||||||
|
if val.Type().String() == "dns.IPSECKEY" {
|
||||||
|
// Field(2) is GatewayType, must be 1
|
||||||
|
if val.Field(2).Uint() != 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
// It must be a slice of 4, even if it is 16, we encode
|
// It must be a slice of 4, even if it is 16, we encode
|
||||||
// only the first 4
|
// only the first 4
|
||||||
if off+net.IPv4len > lenmsg {
|
if off+net.IPv4len > lenmsg {
|
||||||
@@ -676,6 +644,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||||||
return lenmsg, &Error{err: "overflow packing a"}
|
return lenmsg, &Error{err: "overflow packing a"}
|
||||||
}
|
}
|
||||||
case `dns:"aaaa"`:
|
case `dns:"aaaa"`:
|
||||||
|
if val.Type().String() == "dns.IPSECKEY" {
|
||||||
|
// Field(2) is GatewayType, must be 2
|
||||||
|
if val.Field(2).Uint() != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
if fv.Len() == 0 {
|
if fv.Len() == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -694,58 +668,49 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||||||
if val.Field(i).Len() == 0 {
|
if val.Field(i).Len() == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var bitmapbyte uint16
|
off1 := off
|
||||||
for j := 0; j < val.Field(i).Len(); j++ {
|
for j := 0; j < val.Field(i).Len(); j++ {
|
||||||
serv := uint16((fv.Index(j).Uint()))
|
serv := int(fv.Index(j).Uint())
|
||||||
bitmapbyte = uint16(serv / 8)
|
if off+serv/8+1 > len(msg) {
|
||||||
if int(bitmapbyte) > lenmsg {
|
return len(msg), &Error{err: "overflow packing wks"}
|
||||||
return lenmsg, &Error{err: "overflow packing wks"}
|
}
|
||||||
|
msg[off+serv/8] |= byte(1 << (7 - uint(serv%8)))
|
||||||
|
if off+serv/8+1 > off1 {
|
||||||
|
off1 = off + serv/8 + 1
|
||||||
}
|
}
|
||||||
bit := uint16(serv) - bitmapbyte*8
|
|
||||||
msg[bitmapbyte] = byte(1 << (7 - bit))
|
|
||||||
}
|
}
|
||||||
off += int(bitmapbyte)
|
off = off1
|
||||||
case `dns:"nsec"`: // NSEC/NSEC3
|
case `dns:"nsec"`: // NSEC/NSEC3
|
||||||
// This is the uint16 type bitmap
|
// This is the uint16 type bitmap
|
||||||
if val.Field(i).Len() == 0 {
|
if val.Field(i).Len() == 0 {
|
||||||
// Do absolutely nothing
|
// Do absolutely nothing
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
var lastwindow, lastlength uint16
|
||||||
lastwindow := uint16(0)
|
|
||||||
length := uint16(0)
|
|
||||||
if off+2 > lenmsg {
|
|
||||||
return lenmsg, &Error{err: "overflow packing nsecx"}
|
|
||||||
}
|
|
||||||
for j := 0; j < val.Field(i).Len(); j++ {
|
for j := 0; j < val.Field(i).Len(); j++ {
|
||||||
t := uint16((fv.Index(j).Uint()))
|
t := uint16(fv.Index(j).Uint())
|
||||||
window := uint16(t / 256)
|
window := t / 256
|
||||||
if lastwindow != window {
|
length := (t-window*256)/8 + 1
|
||||||
|
if window > lastwindow && lastlength != 0 {
|
||||||
// New window, jump to the new offset
|
// New window, jump to the new offset
|
||||||
off += int(length) + 3
|
off += int(lastlength) + 2
|
||||||
if off > lenmsg {
|
lastlength = 0
|
||||||
return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
length = (t - window*256) / 8
|
if window < lastwindow || length < lastlength {
|
||||||
bit := t - (window * 256) - (length * 8)
|
return len(msg), &Error{err: "nsec bits out of order"}
|
||||||
if off+2+int(length) > lenmsg {
|
}
|
||||||
return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
|
if off+2+int(length) > len(msg) {
|
||||||
|
return len(msg), &Error{err: "overflow packing nsec"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the window #
|
// Setting the window #
|
||||||
msg[off] = byte(window)
|
msg[off] = byte(window)
|
||||||
// Setting the octets length
|
// Setting the octets length
|
||||||
msg[off+1] = byte(length + 1)
|
msg[off+1] = byte(length)
|
||||||
// Setting the bit value for the type in the right octet
|
// Setting the bit value for the type in the right octet
|
||||||
msg[off+2+int(length)] |= byte(1 << (7 - bit))
|
msg[off+1+int(length)] |= byte(1 << (7 - (t % 8)))
|
||||||
lastwindow = window
|
lastwindow, lastlength = window, length
|
||||||
}
|
|
||||||
off += 2 + int(length)
|
|
||||||
off++
|
|
||||||
if off > lenmsg {
|
|
||||||
return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
|
|
||||||
}
|
}
|
||||||
|
off += int(lastlength) + 2
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
off, err = packStructValue(fv, msg, off, compression, compress)
|
off, err = packStructValue(fv, msg, off, compression, compress)
|
||||||
@@ -821,6 +786,13 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||||||
copy(msg[off:off+len(b64)], b64)
|
copy(msg[off:off+len(b64)], b64)
|
||||||
off += len(b64)
|
off += len(b64)
|
||||||
case `dns:"domain-name"`:
|
case `dns:"domain-name"`:
|
||||||
|
if val.Type().String() == "dns.IPSECKEY" {
|
||||||
|
// Field(2) is GatewayType, 1 and 2 or used for addresses
|
||||||
|
x := val.Field(2).Uint()
|
||||||
|
if x == 1 || x == 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil {
|
if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil {
|
||||||
return lenmsg, err
|
return lenmsg, err
|
||||||
}
|
}
|
||||||
@@ -859,6 +831,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||||||
// length of string. String is RAW (not encoded in hex, nor base64)
|
// length of string. String is RAW (not encoded in hex, nor base64)
|
||||||
copy(msg[off:off+len(s)], s)
|
copy(msg[off:off+len(s)], s)
|
||||||
off += len(s)
|
off += len(s)
|
||||||
|
case `dns:"octet"`:
|
||||||
|
bytesTmp := make([]byte, 256)
|
||||||
|
off, err = packOctetString(fv.String(), msg, off, bytesTmp)
|
||||||
|
if err != nil {
|
||||||
|
return lenmsg, err
|
||||||
|
}
|
||||||
case `dns:"txt"`:
|
case `dns:"txt"`:
|
||||||
fallthrough
|
fallthrough
|
||||||
case "":
|
case "":
|
||||||
@@ -890,17 +868,11 @@ func packStructCompress(any interface{}, msg []byte, off int, compression map[st
|
|||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(miek): Fix use of rdlength here
|
|
||||||
|
|
||||||
// Unpack a reflect.StructValue from msg.
|
// Unpack a reflect.StructValue from msg.
|
||||||
// Same restrictions as packStructValue.
|
// Same restrictions as packStructValue.
|
||||||
func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) {
|
func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) {
|
||||||
var lenrd int
|
|
||||||
lenmsg := len(msg)
|
lenmsg := len(msg)
|
||||||
for i := 0; i < val.NumField(); i++ {
|
for i := 0; i < val.NumField(); i++ {
|
||||||
if lenrd != 0 && lenrd == off {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if off > lenmsg {
|
if off > lenmsg {
|
||||||
return lenmsg, &Error{"bad offset unpacking"}
|
return lenmsg, &Error{"bad offset unpacking"}
|
||||||
}
|
}
|
||||||
@@ -912,7 +884,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
// therefore it's expected that this interface would be PrivateRdata
|
// therefore it's expected that this interface would be PrivateRdata
|
||||||
switch data := fv.Interface().(type) {
|
switch data := fv.Interface().(type) {
|
||||||
case PrivateRdata:
|
case PrivateRdata:
|
||||||
n, err := data.Unpack(msg[off:lenrd])
|
n, err := data.Unpack(msg[off:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lenmsg, err
|
return lenmsg, err
|
||||||
}
|
}
|
||||||
@@ -926,9 +898,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")}
|
return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")}
|
||||||
case `dns:"domain-name"`:
|
case `dns:"domain-name"`:
|
||||||
// HIP record slice of name (or none)
|
// HIP record slice of name (or none)
|
||||||
servers := make([]string, 0)
|
var servers []string
|
||||||
var s string
|
var s string
|
||||||
for off < lenrd {
|
for off < lenmsg {
|
||||||
s, off, err = UnpackDomainName(msg, off)
|
s, off, err = UnpackDomainName(msg, off)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lenmsg, err
|
return lenmsg, err
|
||||||
@@ -937,30 +909,30 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(servers))
|
fv.Set(reflect.ValueOf(servers))
|
||||||
case `dns:"txt"`:
|
case `dns:"txt"`:
|
||||||
if off == lenmsg || lenrd == off {
|
if off == lenmsg {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var txt []string
|
var txt []string
|
||||||
txt, off, err = unpackTxt(msg, off, lenrd)
|
txt, off, err = unpackTxt(msg, off)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lenmsg, err
|
return lenmsg, err
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(txt))
|
fv.Set(reflect.ValueOf(txt))
|
||||||
case `dns:"opt"`: // edns0
|
case `dns:"opt"`: // edns0
|
||||||
if off == lenrd {
|
if off == lenmsg {
|
||||||
// This is an EDNS0 (OPT Record) with no rdata
|
// This is an EDNS0 (OPT Record) with no rdata
|
||||||
// We can safely return here.
|
// We can safely return here.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
edns := make([]EDNS0, 0)
|
var edns []EDNS0
|
||||||
Option:
|
Option:
|
||||||
code := uint16(0)
|
code := uint16(0)
|
||||||
if off+2 > lenmsg {
|
if off+4 > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking opt"}
|
return lenmsg, &Error{err: "overflow unpacking opt"}
|
||||||
}
|
}
|
||||||
code, off = unpackUint16(msg, off)
|
code, off = unpackUint16(msg, off)
|
||||||
optlen, off1 := unpackUint16(msg, off)
|
optlen, off1 := unpackUint16(msg, off)
|
||||||
if off1+int(optlen) > lenrd {
|
if off1+int(optlen) > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking opt"}
|
return lenmsg, &Error{err: "overflow unpacking opt"}
|
||||||
}
|
}
|
||||||
switch code {
|
switch code {
|
||||||
@@ -1017,27 +989,44 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
edns = append(edns, e)
|
edns = append(edns, e)
|
||||||
off = off1 + int(optlen)
|
off = off1 + int(optlen)
|
||||||
default:
|
default:
|
||||||
// do nothing?
|
e := new(EDNS0_LOCAL)
|
||||||
|
e.Code = code
|
||||||
|
if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
|
||||||
|
return lenmsg, err
|
||||||
|
}
|
||||||
|
edns = append(edns, e)
|
||||||
off = off1 + int(optlen)
|
off = off1 + int(optlen)
|
||||||
}
|
}
|
||||||
if off < lenrd {
|
if off < lenmsg {
|
||||||
goto Option
|
goto Option
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(edns))
|
fv.Set(reflect.ValueOf(edns))
|
||||||
case `dns:"a"`:
|
case `dns:"a"`:
|
||||||
if off == lenrd {
|
if val.Type().String() == "dns.IPSECKEY" {
|
||||||
|
// Field(2) is GatewayType, must be 1
|
||||||
|
if val.Field(2).Uint() != 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if off == lenmsg {
|
||||||
break // dyn. update
|
break // dyn. update
|
||||||
}
|
}
|
||||||
if off+net.IPv4len > lenrd || off+net.IPv4len > lenmsg {
|
if off+net.IPv4len > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking a"}
|
return lenmsg, &Error{err: "overflow unpacking a"}
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3])))
|
fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3])))
|
||||||
off += net.IPv4len
|
off += net.IPv4len
|
||||||
case `dns:"aaaa"`:
|
case `dns:"aaaa"`:
|
||||||
if off == lenrd {
|
if val.Type().String() == "dns.IPSECKEY" {
|
||||||
|
// Field(2) is GatewayType, must be 2
|
||||||
|
if val.Field(2).Uint() != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if off == lenmsg {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if off+net.IPv6len > lenrd || off+net.IPv6len > lenmsg {
|
if off+net.IPv6len > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking aaaa"}
|
return lenmsg, &Error{err: "overflow unpacking aaaa"}
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4],
|
fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4],
|
||||||
@@ -1046,9 +1035,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
off += net.IPv6len
|
off += net.IPv6len
|
||||||
case `dns:"wks"`:
|
case `dns:"wks"`:
|
||||||
// Rest of the record is the bitmap
|
// Rest of the record is the bitmap
|
||||||
serv := make([]uint16, 0)
|
var serv []uint16
|
||||||
j := 0
|
j := 0
|
||||||
for off < lenrd {
|
for off < lenmsg {
|
||||||
if off+1 > lenmsg {
|
if off+1 > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking wks"}
|
return lenmsg, &Error{err: "overflow unpacking wks"}
|
||||||
}
|
}
|
||||||
@@ -1083,36 +1072,39 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(serv))
|
fv.Set(reflect.ValueOf(serv))
|
||||||
case `dns:"nsec"`: // NSEC/NSEC3
|
case `dns:"nsec"`: // NSEC/NSEC3
|
||||||
if off == lenrd {
|
if off == len(msg) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Rest of the record is the type bitmap
|
// Rest of the record is the type bitmap
|
||||||
if off+2 > lenrd || off+2 > lenmsg {
|
var nsec []uint16
|
||||||
return lenmsg, &Error{err: "overflow unpacking nsecx"}
|
|
||||||
}
|
|
||||||
nsec := make([]uint16, 0)
|
|
||||||
length := 0
|
length := 0
|
||||||
window := 0
|
window := 0
|
||||||
for off+2 < lenrd {
|
lastwindow := -1
|
||||||
|
for off < len(msg) {
|
||||||
|
if off+2 > len(msg) {
|
||||||
|
return len(msg), &Error{err: "overflow unpacking nsecx"}
|
||||||
|
}
|
||||||
window = int(msg[off])
|
window = int(msg[off])
|
||||||
length = int(msg[off+1])
|
length = int(msg[off+1])
|
||||||
//println("off, windows, length, end", off, window, length, endrr)
|
off += 2
|
||||||
|
if window <= lastwindow {
|
||||||
|
// RFC 4034: Blocks are present in the NSEC RR RDATA in
|
||||||
|
// increasing numerical order.
|
||||||
|
return len(msg), &Error{err: "out of order NSEC block"}
|
||||||
|
}
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
// A length window of zero is strange. If there
|
// RFC 4034: Blocks with no types present MUST NOT be included.
|
||||||
// the window should not have been specified. Bail out
|
return len(msg), &Error{err: "empty NSEC block"}
|
||||||
// println("dns: length == 0 when unpacking NSEC")
|
|
||||||
return lenmsg, &Error{err: "overflow unpacking nsecx"}
|
|
||||||
}
|
}
|
||||||
if length > 32 {
|
if length > 32 {
|
||||||
return lenmsg, &Error{err: "overflow unpacking nsecx"}
|
return len(msg), &Error{err: "NSEC block too long"}
|
||||||
|
}
|
||||||
|
if off+length > len(msg) {
|
||||||
|
return len(msg), &Error{err: "overflowing NSEC block"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the bytes in the window - and check the bit settings...
|
// Walk the bytes in the window and extract the type bits
|
||||||
off += 2
|
|
||||||
for j := 0; j < length; j++ {
|
for j := 0; j < length; j++ {
|
||||||
if off+j+1 > lenmsg {
|
|
||||||
return lenmsg, &Error{err: "overflow unpacking nsecx"}
|
|
||||||
}
|
|
||||||
b := msg[off+j]
|
b := msg[off+j]
|
||||||
// Check the bits one by one, and set the type
|
// Check the bits one by one, and set the type
|
||||||
if b&0x80 == 0x80 {
|
if b&0x80 == 0x80 {
|
||||||
@@ -1141,6 +1133,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
off += length
|
off += length
|
||||||
|
lastwindow = window
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(nsec))
|
fv.Set(reflect.ValueOf(nsec))
|
||||||
}
|
}
|
||||||
@@ -1150,7 +1143,12 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
return lenmsg, err
|
return lenmsg, err
|
||||||
}
|
}
|
||||||
if val.Type().Field(i).Name == "Hdr" {
|
if val.Type().Field(i).Name == "Hdr" {
|
||||||
lenrd = off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint())
|
lenrd := off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint())
|
||||||
|
if lenrd > lenmsg {
|
||||||
|
return lenmsg, &Error{err: "overflowing header size"}
|
||||||
|
}
|
||||||
|
msg = msg[:lenrd]
|
||||||
|
lenmsg = len(msg)
|
||||||
}
|
}
|
||||||
case reflect.Uint8:
|
case reflect.Uint8:
|
||||||
if off == lenmsg {
|
if off == lenmsg {
|
||||||
@@ -1181,6 +1179,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])))
|
fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])))
|
||||||
off += 4
|
off += 4
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
|
if off == lenmsg {
|
||||||
|
break
|
||||||
|
}
|
||||||
switch val.Type().Field(i).Tag {
|
switch val.Type().Field(i).Tag {
|
||||||
default:
|
default:
|
||||||
if off+8 > lenmsg {
|
if off+8 > lenmsg {
|
||||||
@@ -1206,32 +1207,42 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||||||
switch val.Type().Field(i).Tag {
|
switch val.Type().Field(i).Tag {
|
||||||
default:
|
default:
|
||||||
return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")}
|
return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")}
|
||||||
|
case `dns:"octet"`:
|
||||||
|
s = string(msg[off:])
|
||||||
|
off = lenmsg
|
||||||
case `dns:"hex"`:
|
case `dns:"hex"`:
|
||||||
hexend := lenrd
|
hexend := lenmsg
|
||||||
if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
|
if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
|
||||||
hexend = off + int(val.FieldByName("HitLength").Uint())
|
hexend = off + int(val.FieldByName("HitLength").Uint())
|
||||||
}
|
}
|
||||||
if hexend > lenrd || hexend > lenmsg {
|
if hexend > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking hex"}
|
return lenmsg, &Error{err: "overflow unpacking HIP hex"}
|
||||||
}
|
}
|
||||||
s = hex.EncodeToString(msg[off:hexend])
|
s = hex.EncodeToString(msg[off:hexend])
|
||||||
off = hexend
|
off = hexend
|
||||||
case `dns:"base64"`:
|
case `dns:"base64"`:
|
||||||
// Rest of the RR is base64 encoded value
|
// Rest of the RR is base64 encoded value
|
||||||
b64end := lenrd
|
b64end := lenmsg
|
||||||
if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
|
if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
|
||||||
b64end = off + int(val.FieldByName("PublicKeyLength").Uint())
|
b64end = off + int(val.FieldByName("PublicKeyLength").Uint())
|
||||||
}
|
}
|
||||||
if b64end > lenrd || b64end > lenmsg {
|
if b64end > lenmsg {
|
||||||
return lenmsg, &Error{err: "overflow unpacking base64"}
|
return lenmsg, &Error{err: "overflow unpacking HIP base64"}
|
||||||
}
|
}
|
||||||
s = toBase64(msg[off:b64end])
|
s = toBase64(msg[off:b64end])
|
||||||
off = b64end
|
off = b64end
|
||||||
case `dns:"cdomain-name"`:
|
case `dns:"cdomain-name"`:
|
||||||
fallthrough
|
fallthrough
|
||||||
case `dns:"domain-name"`:
|
case `dns:"domain-name"`:
|
||||||
if off == lenmsg {
|
if val.Type().String() == "dns.IPSECKEY" {
|
||||||
// zero rdata foo, OK for dyn. updates
|
// Field(2) is GatewayType, 1 and 2 or used for addresses
|
||||||
|
x := val.Field(2).Uint()
|
||||||
|
if x == 1 || x == 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if off == lenmsg && int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) == 0 {
|
||||||
|
// zero rdata is ok for dyn updates, but only if rdlength is 0
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s, off, err = UnpackDomainName(msg, off)
|
s, off, err = UnpackDomainName(msg, off)
|
||||||
@@ -1375,7 +1386,7 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
|||||||
}
|
}
|
||||||
end := off + int(h.Rdlength)
|
end := off + int(h.Rdlength)
|
||||||
// make an rr of that type and re-unpack.
|
// make an rr of that type and re-unpack.
|
||||||
mk, known := typeToRR[h.Rrtype]
|
mk, known := TypeToRR[h.Rrtype]
|
||||||
if !known {
|
if !known {
|
||||||
rr = new(RFC3597)
|
rr = new(RFC3597)
|
||||||
} else {
|
} else {
|
||||||
@@ -1388,6 +1399,32 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
|||||||
return rr, off, err
|
return rr, off, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unpackRRslice unpacks msg[off:] into an []RR.
|
||||||
|
// If we cannot unpack the whole array, then it will return nil
|
||||||
|
func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
|
||||||
|
var r RR
|
||||||
|
// Optimistically make dst be the length that was sent
|
||||||
|
dst := make([]RR, 0, l)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
off1 := off
|
||||||
|
r, off, err = UnpackRR(msg, off)
|
||||||
|
if err != nil {
|
||||||
|
off = len(msg)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// If offset does not increase anymore, l is a lie
|
||||||
|
if off1 == off {
|
||||||
|
l = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
dst = append(dst, r)
|
||||||
|
}
|
||||||
|
if err != nil && off == len(msg) {
|
||||||
|
dst = nil
|
||||||
|
}
|
||||||
|
return dst, off, err
|
||||||
|
}
|
||||||
|
|
||||||
// Reverse a map
|
// Reverse a map
|
||||||
func reverseInt8(m map[uint8]string) map[string]uint8 {
|
func reverseInt8(m map[uint8]string) map[string]uint8 {
|
||||||
n := make(map[string]uint8)
|
n := make(map[string]uint8)
|
||||||
@@ -1586,52 +1623,48 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
|||||||
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
||||||
dns.Rcode = int(dh.Bits & 0xF)
|
dns.Rcode = int(dh.Bits & 0xF)
|
||||||
|
|
||||||
// Arrays.
|
// Optimistically use the count given to us in the header
|
||||||
dns.Question = make([]Question, dh.Qdcount)
|
dns.Question = make([]Question, 0, int(dh.Qdcount))
|
||||||
dns.Answer = make([]RR, dh.Ancount)
|
|
||||||
dns.Ns = make([]RR, dh.Nscount)
|
|
||||||
dns.Extra = make([]RR, dh.Arcount)
|
|
||||||
|
|
||||||
for i := 0; i < len(dns.Question); i++ {
|
var q Question
|
||||||
off, err = UnpackStruct(&dns.Question[i], msg, off)
|
for i := 0; i < int(dh.Qdcount); i++ {
|
||||||
|
off1 := off
|
||||||
|
off, err = UnpackStruct(&q, msg, off)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Even if Truncated is set, we only will set ErrTruncated if we
|
||||||
|
// actually got the questions
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
|
||||||
// If we see a TC bit being set we return here, without
|
dh.Qdcount = uint16(i)
|
||||||
// an error, because technically it isn't an error. So return
|
break
|
||||||
// without parsing the potentially corrupt packet and hitting an error.
|
|
||||||
// TODO(miek): this isn't the best strategy!
|
|
||||||
if dns.Truncated {
|
|
||||||
dns.Answer = nil
|
|
||||||
dns.Ns = nil
|
|
||||||
dns.Extra = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for i := 0; i < len(dns.Answer); i++ {
|
|
||||||
dns.Answer[i], off, err = UnpackRR(msg, off)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
dns.Question = append(dns.Question, q)
|
||||||
}
|
}
|
||||||
for i := 0; i < len(dns.Ns); i++ {
|
|
||||||
dns.Ns[i], off, err = UnpackRR(msg, off)
|
dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off)
|
||||||
if err != nil {
|
// The header counts might have been wrong so we need to update it
|
||||||
return err
|
dh.Ancount = uint16(len(dns.Answer))
|
||||||
}
|
if err == nil {
|
||||||
|
dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off)
|
||||||
}
|
}
|
||||||
for i := 0; i < len(dns.Extra); i++ {
|
// The header counts might have been wrong so we need to update it
|
||||||
dns.Extra[i], off, err = UnpackRR(msg, off)
|
dh.Nscount = uint16(len(dns.Ns))
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// The header counts might have been wrong so we need to update it
|
||||||
|
dh.Arcount = uint16(len(dns.Extra))
|
||||||
if off != len(msg) {
|
if off != len(msg) {
|
||||||
// TODO(miek) make this an error?
|
// TODO(miek) make this an error?
|
||||||
// use PackOpt to let people tell how detailed the error reporting should be?
|
// use PackOpt to let people tell how detailed the error reporting should be?
|
||||||
// println("dns: extra bytes in dns packet", off, "<", len(msg))
|
// println("dns: extra bytes in dns packet", off, "<", len(msg))
|
||||||
|
} else if dns.Truncated {
|
||||||
|
// Whether we ran into a an error or not, we want to return that it
|
||||||
|
// was truncated
|
||||||
|
err = ErrTruncated
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a complete message to a string with dig-like output.
|
// Convert a complete message to a string with dig-like output.
|
||||||
@@ -1863,9 +1896,18 @@ func Copy(r RR) RR {
|
|||||||
return r1
|
return r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len returns the length (in octets) of the uncompressed RR in wire format.
|
||||||
|
func Len(r RR) int {
|
||||||
|
return r.len()
|
||||||
|
}
|
||||||
|
|
||||||
// Copy returns a new *Msg which is a deep-copy of dns.
|
// Copy returns a new *Msg which is a deep-copy of dns.
|
||||||
func (dns *Msg) Copy() *Msg {
|
func (dns *Msg) Copy() *Msg {
|
||||||
r1 := new(Msg)
|
return dns.CopyTo(new(Msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyTo copies the contents to the provided message using a deep-copy and returns the copy.
|
||||||
|
func (dns *Msg) CopyTo(r1 *Msg) *Msg {
|
||||||
r1.MsgHdr = dns.MsgHdr
|
r1.MsgHdr = dns.MsgHdr
|
||||||
r1.Compress = dns.Compress
|
r1.Compress = dns.Compress
|
||||||
|
|
||||||
@@ -1874,25 +1916,34 @@ func (dns *Msg) Copy() *Msg {
|
|||||||
copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
|
copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra))
|
||||||
|
var rri int
|
||||||
|
|
||||||
if len(dns.Answer) > 0 {
|
if len(dns.Answer) > 0 {
|
||||||
r1.Answer = make([]RR, len(dns.Answer))
|
rrbegin := rri
|
||||||
for i := 0; i < len(dns.Answer); i++ {
|
for i := 0; i < len(dns.Answer); i++ {
|
||||||
r1.Answer[i] = dns.Answer[i].copy()
|
rrArr[rri] = dns.Answer[i].copy()
|
||||||
|
rri++
|
||||||
}
|
}
|
||||||
|
r1.Answer = rrArr[rrbegin:rri:rri]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dns.Ns) > 0 {
|
if len(dns.Ns) > 0 {
|
||||||
r1.Ns = make([]RR, len(dns.Ns))
|
rrbegin := rri
|
||||||
for i := 0; i < len(dns.Ns); i++ {
|
for i := 0; i < len(dns.Ns); i++ {
|
||||||
r1.Ns[i] = dns.Ns[i].copy()
|
rrArr[rri] = dns.Ns[i].copy()
|
||||||
|
rri++
|
||||||
}
|
}
|
||||||
|
r1.Ns = rrArr[rrbegin:rri:rri]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dns.Extra) > 0 {
|
if len(dns.Extra) > 0 {
|
||||||
r1.Extra = make([]RR, len(dns.Extra))
|
rrbegin := rri
|
||||||
for i := 0; i < len(dns.Extra); i++ {
|
for i := 0; i < len(dns.Extra); i++ {
|
||||||
r1.Extra[i] = dns.Extra[i].copy()
|
rrArr[rri] = dns.Extra[i].copy()
|
||||||
|
rri++
|
||||||
}
|
}
|
||||||
|
r1.Extra = rrArr[rrbegin:rri:rri]
|
||||||
}
|
}
|
||||||
|
|
||||||
return r1
|
return r1
|
||||||
|
|||||||
2
vendor/github.com/miekg/dns/nsecx.go
generated
vendored
2
vendor/github.com/miekg/dns/nsecx.go
generated
vendored
@@ -50,6 +50,8 @@ func HashName(label string, ha uint8, iter uint16, salt string) string {
|
|||||||
return toBase32(nsec3)
|
return toBase32(nsec3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Denialer is an interface that should be implemented by types that are used to denial
|
||||||
|
// answers in DNSSEC.
|
||||||
type Denialer interface {
|
type Denialer interface {
|
||||||
// Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
|
// Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
|
||||||
Cover(name string) bool
|
Cover(name string) bool
|
||||||
|
|||||||
23
vendor/github.com/miekg/dns/privaterr.go
generated
vendored
23
vendor/github.com/miekg/dns/privaterr.go
generated
vendored
@@ -1,10 +1,3 @@
|
|||||||
/*
|
|
||||||
PRIVATE RR
|
|
||||||
|
|
||||||
RFC 6895 sets aside a range of type codes for private use. This range
|
|
||||||
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
|
|
||||||
can be used, before requesting an official type code from IANA.
|
|
||||||
*/
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -40,7 +33,7 @@ type PrivateRR struct {
|
|||||||
|
|
||||||
func mkPrivateRR(rrtype uint16) *PrivateRR {
|
func mkPrivateRR(rrtype uint16) *PrivateRR {
|
||||||
// Panics if RR is not an instance of PrivateRR.
|
// Panics if RR is not an instance of PrivateRR.
|
||||||
rrfunc, ok := typeToRR[rrtype]
|
rrfunc, ok := TypeToRR[rrtype]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
|
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
|
||||||
}
|
}
|
||||||
@@ -50,11 +43,13 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
|
|||||||
case *PrivateRR:
|
case *PrivateRR:
|
||||||
return rr
|
return rr
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr))
|
panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header return the RR header of r.
|
||||||
func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
|
func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
|
||||||
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
|
|
||||||
|
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
|
||||||
|
|
||||||
// Private len and copy parts to satisfy RR interface.
|
// Private len and copy parts to satisfy RR interface.
|
||||||
func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
|
func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
|
||||||
@@ -76,7 +71,7 @@ func (r *PrivateRR) copy() RR {
|
|||||||
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
||||||
rtypestr = strings.ToUpper(rtypestr)
|
rtypestr = strings.ToUpper(rtypestr)
|
||||||
|
|
||||||
typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
||||||
TypeToString[rtype] = rtypestr
|
TypeToString[rtype] = rtypestr
|
||||||
StringToType[rtypestr] = rtype
|
StringToType[rtypestr] = rtype
|
||||||
|
|
||||||
@@ -91,9 +86,9 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
|
|||||||
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
||||||
// be an issue (basically parsing TXT becomes hard)
|
// be an issue (basically parsing TXT becomes hard)
|
||||||
switch l = <-c; l.value {
|
switch l = <-c; l.value {
|
||||||
case _NEWLINE, _EOF:
|
case zNewline, zEOF:
|
||||||
break FETCH
|
break FETCH
|
||||||
case _STRING:
|
case zString:
|
||||||
text = append(text, l.token)
|
text = append(text, l.token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +108,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
|
|||||||
func PrivateHandleRemove(rtype uint16) {
|
func PrivateHandleRemove(rtype uint16) {
|
||||||
rtypestr, ok := TypeToString[rtype]
|
rtypestr, ok := TypeToString[rtype]
|
||||||
if ok {
|
if ok {
|
||||||
delete(typeToRR, rtype)
|
delete(TypeToRR, rtype)
|
||||||
delete(TypeToString, rtype)
|
delete(TypeToString, rtype)
|
||||||
delete(typeToparserFunc, rtype)
|
delete(typeToparserFunc, rtype)
|
||||||
delete(StringToType, rtypestr)
|
delete(StringToType, rtypestr)
|
||||||
|
|||||||
6
vendor/github.com/miekg/dns/rawmsg.go
generated
vendored
6
vendor/github.com/miekg/dns/rawmsg.go
generated
vendored
@@ -21,7 +21,7 @@ func rawSetQuestionLen(msg []byte, i uint16) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// rawSetAnswerLen sets the lenght of the answer section.
|
// rawSetAnswerLen sets the length of the answer section.
|
||||||
func rawSetAnswerLen(msg []byte, i uint16) bool {
|
func rawSetAnswerLen(msg []byte, i uint16) bool {
|
||||||
if len(msg) < 8 {
|
if len(msg) < 8 {
|
||||||
return false
|
return false
|
||||||
@@ -30,7 +30,7 @@ func rawSetAnswerLen(msg []byte, i uint16) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// rawSetsNsLen sets the lenght of the authority section.
|
// rawSetsNsLen sets the length of the authority section.
|
||||||
func rawSetNsLen(msg []byte, i uint16) bool {
|
func rawSetNsLen(msg []byte, i uint16) bool {
|
||||||
if len(msg) < 10 {
|
if len(msg) < 10 {
|
||||||
return false
|
return false
|
||||||
@@ -39,7 +39,7 @@ func rawSetNsLen(msg []byte, i uint16) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// rawSetExtraLen sets the lenght of the additional section.
|
// rawSetExtraLen sets the length of the additional section.
|
||||||
func rawSetExtraLen(msg []byte, i uint16) bool {
|
func rawSetExtraLen(msg []byte, i uint16) bool {
|
||||||
if len(msg) < 12 {
|
if len(msg) < 12 {
|
||||||
return false
|
return false
|
||||||
|
|||||||
84
vendor/github.com/miekg/dns/sanitize.go
generated
vendored
Normal file
84
vendor/github.com/miekg/dns/sanitize.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
// Dedup removes identical RRs from rrs. It preserves the original ordering.
|
||||||
|
// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
|
||||||
|
// rrs.
|
||||||
|
// m is used to store the RRs temporay. If it is nil a new map will be allocated.
|
||||||
|
func Dedup(rrs []RR, m map[string]RR) []RR {
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]RR)
|
||||||
|
}
|
||||||
|
// Save the keys, so we don't have to call normalizedString twice.
|
||||||
|
keys := make([]*string, 0, len(rrs))
|
||||||
|
|
||||||
|
for _, r := range rrs {
|
||||||
|
key := normalizedString(r)
|
||||||
|
keys = append(keys, &key)
|
||||||
|
if _, ok := m[key]; ok {
|
||||||
|
// Shortest TTL wins.
|
||||||
|
if m[key].Header().Ttl > r.Header().Ttl {
|
||||||
|
m[key].Header().Ttl = r.Header().Ttl
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
m[key] = r
|
||||||
|
}
|
||||||
|
// If the length of the result map equals the amount of RRs we got,
|
||||||
|
// it means they were all different. We can then just return the original rrset.
|
||||||
|
if len(m) == len(rrs) {
|
||||||
|
return rrs
|
||||||
|
}
|
||||||
|
|
||||||
|
j := 0
|
||||||
|
for i, r := range rrs {
|
||||||
|
// If keys[i] lives in the map, we should copy and remove it.
|
||||||
|
if _, ok := m[*keys[i]]; ok {
|
||||||
|
delete(m, *keys[i])
|
||||||
|
rrs[j] = r
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rrs[:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizedString returns a normalized string from r. The TTL
|
||||||
|
// is removed and the domain name is lowercased. We go from this:
|
||||||
|
// DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to:
|
||||||
|
// lowercasename<TAB>CLASS<TAB>TYPE...
|
||||||
|
func normalizedString(r RR) string {
|
||||||
|
// A string Go DNS makes has: domainname<TAB>TTL<TAB>...
|
||||||
|
b := []byte(r.String())
|
||||||
|
|
||||||
|
// find the first non-escaped tab, then another, so we capture where the TTL lives.
|
||||||
|
esc := false
|
||||||
|
ttlStart, ttlEnd := 0, 0
|
||||||
|
for i := 0; i < len(b) && ttlEnd == 0; i++ {
|
||||||
|
switch {
|
||||||
|
case b[i] == '\\':
|
||||||
|
esc = !esc
|
||||||
|
case b[i] == '\t' && !esc:
|
||||||
|
if ttlStart == 0 {
|
||||||
|
ttlStart = i
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ttlEnd == 0 {
|
||||||
|
ttlEnd = i
|
||||||
|
}
|
||||||
|
case b[i] >= 'A' && b[i] <= 'Z' && !esc:
|
||||||
|
b[i] += 32
|
||||||
|
default:
|
||||||
|
esc = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove TTL.
|
||||||
|
copy(b[ttlStart:], b[ttlEnd:])
|
||||||
|
cut := ttlEnd - ttlStart
|
||||||
|
return string(b[:len(b)-cut])
|
||||||
|
}
|
||||||
311
vendor/github.com/miekg/dns/server.go
generated
vendored
311
vendor/github.com/miekg/dns/server.go
generated
vendored
@@ -4,12 +4,17 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Maximum number of TCP queries before we close the socket.
|
||||||
|
const maxTCPQueries = 128
|
||||||
|
|
||||||
|
// Handler is implemented by any value that implements ServeDNS.
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
ServeDNS(w ResponseWriter, r *Msg)
|
ServeDNS(w ResponseWriter, r *Msg)
|
||||||
}
|
}
|
||||||
@@ -43,9 +48,10 @@ type response struct {
|
|||||||
tsigRequestMAC string
|
tsigRequestMAC string
|
||||||
tsigSecret map[string]string // the tsig secrets
|
tsigSecret map[string]string // the tsig secrets
|
||||||
udp *net.UDPConn // i/o connection if UDP was used
|
udp *net.UDPConn // i/o connection if UDP was used
|
||||||
tcp *net.TCPConn // i/o connection if TCP was used
|
tcp net.Conn // i/o connection if TCP was used
|
||||||
udpSession *sessionUDP // oob data to get egress interface right
|
udpSession *SessionUDP // oob data to get egress interface right
|
||||||
remoteAddr net.Addr // address of the client
|
remoteAddr net.Addr // address of the client
|
||||||
|
writer Writer // writer to output the raw DNS bits
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeMux is an DNS request multiplexer. It matches the
|
// ServeMux is an DNS request multiplexer. It matches the
|
||||||
@@ -72,12 +78,12 @@ var DefaultServeMux = NewServeMux()
|
|||||||
// Handler object that calls f.
|
// Handler object that calls f.
|
||||||
type HandlerFunc func(ResponseWriter, *Msg)
|
type HandlerFunc func(ResponseWriter, *Msg)
|
||||||
|
|
||||||
// ServerDNS calls f(w, r)
|
// ServeDNS calls f(w, r).
|
||||||
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
|
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
|
||||||
f(w, r)
|
f(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailedHandler returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
||||||
func HandleFailed(w ResponseWriter, r *Msg) {
|
func HandleFailed(w ResponseWriter, r *Msg) {
|
||||||
m := new(Msg)
|
m := new(Msg)
|
||||||
m.SetRcode(r, RcodeServerFailure)
|
m.SetRcode(r, RcodeServerFailure)
|
||||||
@@ -87,13 +93,35 @@ func HandleFailed(w ResponseWriter, r *Msg) {
|
|||||||
|
|
||||||
func failedHandler() Handler { return HandlerFunc(HandleFailed) }
|
func failedHandler() Handler { return HandlerFunc(HandleFailed) }
|
||||||
|
|
||||||
// ListenAndServe Starts a server on addresss and network speficied. Invoke handler
|
// ListenAndServe Starts a server on address and network specified Invoke handler
|
||||||
// for incoming queries.
|
// for incoming queries.
|
||||||
func ListenAndServe(addr string, network string, handler Handler) error {
|
func ListenAndServe(addr string, network string, handler Handler) error {
|
||||||
server := &Server{Addr: addr, Net: network, Handler: handler}
|
server := &Server{Addr: addr, Net: network, Handler: handler}
|
||||||
return server.ListenAndServe()
|
return server.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListenAndServeTLS acts like http.ListenAndServeTLS, more information in
|
||||||
|
// http://golang.org/pkg/net/http/#ListenAndServeTLS
|
||||||
|
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
|
||||||
|
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Addr: addr,
|
||||||
|
Net: "tcp-tls",
|
||||||
|
TLSConfig: &config,
|
||||||
|
Handler: handler,
|
||||||
|
}
|
||||||
|
|
||||||
|
return server.ListenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
// ActivateAndServe activates a server with a listener from systemd,
|
// ActivateAndServe activates a server with a listener from systemd,
|
||||||
// l and p should not both be non-nil.
|
// l and p should not both be non-nil.
|
||||||
// If both l and p are not nil only p will be used.
|
// If both l and p are not nil only p will be used.
|
||||||
@@ -121,10 +149,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
|
|||||||
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
|
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
|
||||||
if t != TypeDS {
|
if t != TypeDS {
|
||||||
return h
|
return h
|
||||||
} else {
|
|
||||||
// Continue for DS to see if we have a parent too, if so delegeate to the parent
|
|
||||||
handler = h
|
|
||||||
}
|
}
|
||||||
|
// Continue for DS to see if we have a parent too, if so delegeate to the parent
|
||||||
|
handler = h
|
||||||
}
|
}
|
||||||
off, end = NextLabel(q, off)
|
off, end = NextLabel(q, off)
|
||||||
if end {
|
if end {
|
||||||
@@ -148,7 +175,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
|
|||||||
mux.m.Unlock()
|
mux.m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle adds a handler to the ServeMux for pattern.
|
// HandleFunc adds a handler function to the ServeMux for pattern.
|
||||||
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||||
mux.Handle(pattern, HandlerFunc(handler))
|
mux.Handle(pattern, HandlerFunc(handler))
|
||||||
}
|
}
|
||||||
@@ -158,9 +185,9 @@ func (mux *ServeMux) HandleRemove(pattern string) {
|
|||||||
if pattern == "" {
|
if pattern == "" {
|
||||||
panic("dns: invalid pattern " + pattern)
|
panic("dns: invalid pattern " + pattern)
|
||||||
}
|
}
|
||||||
// don't need a mutex here, because deleting is OK, even if the
|
mux.m.Lock()
|
||||||
// entry is note there.
|
|
||||||
delete(mux.z, Fqdn(pattern))
|
delete(mux.z, Fqdn(pattern))
|
||||||
|
mux.m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeDNS dispatches the request to the handler whose
|
// ServeDNS dispatches the request to the handler whose
|
||||||
@@ -197,14 +224,53 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
|||||||
DefaultServeMux.HandleFunc(pattern, handler)
|
DefaultServeMux.HandleFunc(pattern, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Writer writes raw DNS messages; each call to Write should send an entire message.
|
||||||
|
type Writer interface {
|
||||||
|
io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
|
||||||
|
type Reader interface {
|
||||||
|
// ReadTCP reads a raw message from a TCP connection. Implementations may alter
|
||||||
|
// connection properties, for example the read-deadline.
|
||||||
|
ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
|
||||||
|
// ReadUDP reads a raw message from a UDP connection. Implementations may alter
|
||||||
|
// connection properties, for example the read-deadline.
|
||||||
|
ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultReader is an adapter for the Server struct that implements the Reader interface
|
||||||
|
// using the readTCP and readUDP func of the embedded Server.
|
||||||
|
type defaultReader struct {
|
||||||
|
*Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||||
|
return dr.readTCP(conn, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||||
|
return dr.readUDP(conn, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
|
||||||
|
// Implementations should never return a nil Reader.
|
||||||
|
type DecorateReader func(Reader) Reader
|
||||||
|
|
||||||
|
// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
|
||||||
|
// Implementations should never return a nil Writer.
|
||||||
|
type DecorateWriter func(Writer) Writer
|
||||||
|
|
||||||
// A Server defines parameters for running an DNS server.
|
// A Server defines parameters for running an DNS server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
// Address to listen on, ":dns" if empty.
|
// Address to listen on, ":dns" if empty.
|
||||||
Addr string
|
Addr string
|
||||||
// if "tcp" it will invoke a TCP listener, otherwise an UDP one.
|
// if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one
|
||||||
Net string
|
Net string
|
||||||
// TCP Listener to use, this is to aid in systemd's socket activation.
|
// TCP Listener to use, this is to aid in systemd's socket activation.
|
||||||
Listener net.Listener
|
Listener net.Listener
|
||||||
|
// TLS connection configuration
|
||||||
|
TLSConfig *tls.Config
|
||||||
// UDP "Listener" to use, this is to aid in systemd's socket activation.
|
// UDP "Listener" to use, this is to aid in systemd's socket activation.
|
||||||
PacketConn net.PacketConn
|
PacketConn net.PacketConn
|
||||||
// Handler to invoke, dns.DefaultServeMux if nil.
|
// Handler to invoke, dns.DefaultServeMux if nil.
|
||||||
@@ -221,31 +287,30 @@ type Server struct {
|
|||||||
// Secret(s) for Tsig map[<zonename>]<base64 secret>.
|
// Secret(s) for Tsig map[<zonename>]<base64 secret>.
|
||||||
TsigSecret map[string]string
|
TsigSecret map[string]string
|
||||||
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
|
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
|
||||||
// the handler. It will specfically not check if the query has the QR bit not set.
|
// the handler. It will specifically not check if the query has the QR bit not set.
|
||||||
Unsafe bool
|
Unsafe bool
|
||||||
// If NotifyStartedFunc is set is is called, once the server has started listening.
|
// If NotifyStartedFunc is set it is called once the server has started listening.
|
||||||
NotifyStartedFunc func()
|
NotifyStartedFunc func()
|
||||||
|
// DecorateReader is optional, allows customization of the process that reads raw DNS messages.
|
||||||
|
DecorateReader DecorateReader
|
||||||
|
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||||
|
DecorateWriter DecorateWriter
|
||||||
|
|
||||||
// For graceful shutdown.
|
// Graceful shutdown handling
|
||||||
stopUDP chan bool
|
|
||||||
stopTCP chan bool
|
|
||||||
wgUDP sync.WaitGroup
|
|
||||||
wgTCP sync.WaitGroup
|
|
||||||
|
|
||||||
// make start/shutdown not racy
|
inFlight sync.WaitGroup
|
||||||
lock sync.Mutex
|
|
||||||
|
lock sync.RWMutex
|
||||||
started bool
|
started bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||||
func (srv *Server) ListenAndServe() error {
|
func (srv *Server) ListenAndServe() error {
|
||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
|
defer srv.lock.Unlock()
|
||||||
if srv.started {
|
if srv.started {
|
||||||
return &Error{err: "server already started"}
|
return &Error{err: "server already started"}
|
||||||
}
|
}
|
||||||
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
|
|
||||||
srv.started = true
|
|
||||||
srv.lock.Unlock()
|
|
||||||
addr := srv.Addr
|
addr := srv.Addr
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
addr = ":domain"
|
addr = ":domain"
|
||||||
@@ -263,7 +328,30 @@ func (srv *Server) ListenAndServe() error {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return srv.serveTCP(l)
|
srv.Listener = l
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
|
e = srv.serveTCP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
|
return e
|
||||||
|
case "tcp-tls", "tcp4-tls", "tcp6-tls":
|
||||||
|
network := "tcp"
|
||||||
|
if srv.Net == "tcp4-tls" {
|
||||||
|
network = "tcp4"
|
||||||
|
} else if srv.Net == "tcp6" {
|
||||||
|
network = "tcp6"
|
||||||
|
}
|
||||||
|
|
||||||
|
l, e := tls.Listen(network, addr, srv.TLSConfig)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
srv.Listener = l
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
|
e = srv.serveTCP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
|
return e
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
a, e := net.ResolveUDPAddr(srv.Net, addr)
|
a, e := net.ResolveUDPAddr(srv.Net, addr)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
@@ -276,7 +364,12 @@ func (srv *Server) ListenAndServe() error {
|
|||||||
if e := setUDPSocketOptions(l); e != nil {
|
if e := setUDPSocketOptions(l); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return srv.serveUDP(l)
|
srv.PacketConn = l
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
|
e = srv.serveUDP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
return &Error{err: "bad network"}
|
return &Error{err: "bad network"}
|
||||||
}
|
}
|
||||||
@@ -285,71 +378,62 @@ func (srv *Server) ListenAndServe() error {
|
|||||||
// configured in *Server. Its main use is to start a server from systemd.
|
// configured in *Server. Its main use is to start a server from systemd.
|
||||||
func (srv *Server) ActivateAndServe() error {
|
func (srv *Server) ActivateAndServe() error {
|
||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
|
defer srv.lock.Unlock()
|
||||||
if srv.started {
|
if srv.started {
|
||||||
return &Error{err: "server already started"}
|
return &Error{err: "server already started"}
|
||||||
}
|
}
|
||||||
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
|
pConn := srv.PacketConn
|
||||||
srv.started = true
|
l := srv.Listener
|
||||||
srv.lock.Unlock()
|
if pConn != nil {
|
||||||
if srv.PacketConn != nil {
|
|
||||||
if srv.UDPSize == 0 {
|
if srv.UDPSize == 0 {
|
||||||
srv.UDPSize = MinMsgSize
|
srv.UDPSize = MinMsgSize
|
||||||
}
|
}
|
||||||
if t, ok := srv.PacketConn.(*net.UDPConn); ok {
|
if t, ok := pConn.(*net.UDPConn); ok {
|
||||||
if e := setUDPSocketOptions(t); e != nil {
|
if e := setUDPSocketOptions(t); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return srv.serveUDP(t)
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
|
e := srv.serveUDP(t)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if srv.Listener != nil {
|
if l != nil {
|
||||||
if t, ok := srv.Listener.(*net.TCPListener); ok {
|
srv.started = true
|
||||||
return srv.serveTCP(t)
|
srv.lock.Unlock()
|
||||||
}
|
e := srv.serveTCP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
return &Error{err: "bad listeners"}
|
return &Error{err: "bad listeners"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
|
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
|
||||||
// ActivateAndServe will return. All in progress queries are completed before the server
|
// ActivateAndServe will return. All in progress queries are completed before the server
|
||||||
// is taken down. If the Shutdown is taking longer than the reading timeout and error
|
// is taken down. If the Shutdown is taking longer than the reading timeout an error
|
||||||
// is returned.
|
// is returned.
|
||||||
func (srv *Server) Shutdown() error {
|
func (srv *Server) Shutdown() error {
|
||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
if !srv.started {
|
if !srv.started {
|
||||||
|
srv.lock.Unlock()
|
||||||
return &Error{err: "server not started"}
|
return &Error{err: "server not started"}
|
||||||
}
|
}
|
||||||
srv.started = false
|
srv.started = false
|
||||||
srv.lock.Unlock()
|
srv.lock.Unlock()
|
||||||
net, addr := srv.Net, srv.Addr
|
|
||||||
switch {
|
if srv.PacketConn != nil {
|
||||||
case srv.Listener != nil:
|
srv.PacketConn.Close()
|
||||||
a := srv.Listener.Addr()
|
}
|
||||||
net, addr = a.Network(), a.String()
|
if srv.Listener != nil {
|
||||||
case srv.PacketConn != nil:
|
srv.Listener.Close()
|
||||||
a := srv.PacketConn.LocalAddr()
|
|
||||||
net, addr = a.Network(), a.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fin := make(chan bool)
|
fin := make(chan bool)
|
||||||
switch net {
|
go func() {
|
||||||
case "tcp", "tcp4", "tcp6":
|
srv.inFlight.Wait()
|
||||||
go func() {
|
fin <- true
|
||||||
srv.stopTCP <- true
|
}()
|
||||||
srv.wgTCP.Wait()
|
|
||||||
fin <- true
|
|
||||||
}()
|
|
||||||
|
|
||||||
case "udp", "udp4", "udp6":
|
|
||||||
go func() {
|
|
||||||
srv.stopUDP <- true
|
|
||||||
srv.wgUDP.Wait()
|
|
||||||
fin <- true
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &Client{Net: net}
|
|
||||||
go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(srv.getReadTimeout()):
|
case <-time.After(srv.getReadTimeout()):
|
||||||
@@ -369,14 +453,19 @@ func (srv *Server) getReadTimeout() time.Duration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// serveTCP starts a TCP listener for the server.
|
// serveTCP starts a TCP listener for the server.
|
||||||
// Each request is handled in a seperate goroutine.
|
// Each request is handled in a separate goroutine.
|
||||||
func (srv *Server) serveTCP(l *net.TCPListener) error {
|
func (srv *Server) serveTCP(l net.Listener) error {
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
if srv.NotifyStartedFunc != nil {
|
if srv.NotifyStartedFunc != nil {
|
||||||
srv.NotifyStartedFunc()
|
srv.NotifyStartedFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader := Reader(&defaultReader{srv})
|
||||||
|
if srv.DecorateReader != nil {
|
||||||
|
reader = srv.DecorateReader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
handler := srv.Handler
|
handler := srv.Handler
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = DefaultServeMux
|
handler = DefaultServeMux
|
||||||
@@ -384,27 +473,30 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
|
|||||||
rtimeout := srv.getReadTimeout()
|
rtimeout := srv.getReadTimeout()
|
||||||
// deadline is not used here
|
// deadline is not used here
|
||||||
for {
|
for {
|
||||||
rw, e := l.AcceptTCP()
|
rw, e := l.Accept()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
continue
|
if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
m, e := srv.readTCP(rw, rtimeout)
|
m, e := reader.ReadTCP(rw, rtimeout)
|
||||||
select {
|
srv.lock.RLock()
|
||||||
case <-srv.stopTCP:
|
if !srv.started {
|
||||||
|
srv.lock.RUnlock()
|
||||||
return nil
|
return nil
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
srv.lock.RUnlock()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
srv.wgTCP.Add(1)
|
srv.inFlight.Add(1)
|
||||||
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveUDP starts a UDP listener for the server.
|
// serveUDP starts a UDP listener for the server.
|
||||||
// Each request is handled in a seperate goroutine.
|
// Each request is handled in a separate goroutine.
|
||||||
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
@@ -412,6 +504,11 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||||||
srv.NotifyStartedFunc()
|
srv.NotifyStartedFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader := Reader(&defaultReader{srv})
|
||||||
|
if srv.DecorateReader != nil {
|
||||||
|
reader = srv.DecorateReader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
handler := srv.Handler
|
handler := srv.Handler
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = DefaultServeMux
|
handler = DefaultServeMux
|
||||||
@@ -419,35 +516,39 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||||||
rtimeout := srv.getReadTimeout()
|
rtimeout := srv.getReadTimeout()
|
||||||
// deadline is not used here
|
// deadline is not used here
|
||||||
for {
|
for {
|
||||||
m, s, e := srv.readUDP(l, rtimeout)
|
m, s, e := reader.ReadUDP(l, rtimeout)
|
||||||
select {
|
srv.lock.RLock()
|
||||||
case <-srv.stopUDP:
|
if !srv.started {
|
||||||
|
srv.lock.RUnlock()
|
||||||
return nil
|
return nil
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
srv.lock.RUnlock()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
srv.wgUDP.Add(1)
|
srv.inFlight.Add(1)
|
||||||
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve a new connection.
|
// Serve a new connection.
|
||||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *sessionUDP, t *net.TCPConn) {
|
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
|
||||||
|
defer srv.inFlight.Done()
|
||||||
|
|
||||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||||
q := 0
|
if srv.DecorateWriter != nil {
|
||||||
defer func() {
|
w.writer = srv.DecorateWriter(w)
|
||||||
if u != nil {
|
} else {
|
||||||
srv.wgUDP.Done()
|
w.writer = w
|
||||||
}
|
}
|
||||||
if t != nil {
|
|
||||||
srv.wgTCP.Done()
|
q := 0 // counter for the amount of TCP queries we get
|
||||||
}
|
|
||||||
}()
|
reader := Reader(&defaultReader{srv})
|
||||||
|
if srv.DecorateReader != nil {
|
||||||
|
reader = srv.DecorateReader(reader)
|
||||||
|
}
|
||||||
Redo:
|
Redo:
|
||||||
// Ideally we want use isMsg here before we allocate memory to actually parse the packet.
|
|
||||||
req := new(Msg)
|
req := new(Msg)
|
||||||
err := req.Unpack(m)
|
err := req.Unpack(m)
|
||||||
if err != nil { // Send a FormatError back
|
if err != nil { // Send a FormatError back
|
||||||
@@ -475,6 +576,15 @@ Redo:
|
|||||||
h.ServeDNS(w, req) // Writes back to the client
|
h.ServeDNS(w, req) // Writes back to the client
|
||||||
|
|
||||||
Exit:
|
Exit:
|
||||||
|
if w.tcp == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO(miek): make this number configurable?
|
||||||
|
if q > maxTCPQueries { // close socket after this many queries
|
||||||
|
w.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if w.hijacked {
|
if w.hijacked {
|
||||||
return // client calls Close()
|
return // client calls Close()
|
||||||
}
|
}
|
||||||
@@ -486,21 +596,16 @@ Exit:
|
|||||||
if srv.IdleTimeout != nil {
|
if srv.IdleTimeout != nil {
|
||||||
idleTimeout = srv.IdleTimeout()
|
idleTimeout = srv.IdleTimeout()
|
||||||
}
|
}
|
||||||
m, e := srv.readTCP(w.tcp, idleTimeout)
|
m, e := reader.ReadTCP(w.tcp, idleTimeout)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
q++
|
q++
|
||||||
// TODO(miek): make this number configurable?
|
|
||||||
if q > 128 { // close socket after this many queries
|
|
||||||
w.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
goto Redo
|
goto Redo
|
||||||
}
|
}
|
||||||
w.Close()
|
w.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
|
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
l := make([]byte, 2)
|
l := make([]byte, 2)
|
||||||
n, err := conn.Read(l)
|
n, err := conn.Read(l)
|
||||||
@@ -535,10 +640,10 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) {
|
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
m := make([]byte, srv.UDPSize)
|
m := make([]byte, srv.UDPSize)
|
||||||
n, s, e := readFromSessionUDP(conn, m)
|
n, s, e := ReadFromSessionUDP(conn, m)
|
||||||
if e != nil || n == 0 {
|
if e != nil || n == 0 {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, nil, e
|
return nil, nil, e
|
||||||
@@ -558,7 +663,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = w.Write(data)
|
_, err = w.writer.Write(data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,7 +671,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = w.Write(data)
|
_, err = w.writer.Write(data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,7 +679,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
|||||||
func (w *response) Write(m []byte) (int, error) {
|
func (w *response) Write(m []byte) (int, error) {
|
||||||
switch {
|
switch {
|
||||||
case w.udp != nil:
|
case w.udp != nil:
|
||||||
n, err := writeToSessionUDP(w.udp, m, w.udpSession)
|
n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
|
||||||
return n, err
|
return n, err
|
||||||
case w.tcp != nil:
|
case w.tcp != nil:
|
||||||
lm := len(m)
|
lm := len(m)
|
||||||
|
|||||||
74
vendor/github.com/miekg/dns/sig0.go
generated
vendored
74
vendor/github.com/miekg/dns/sig0.go
generated
vendored
@@ -1,25 +1,9 @@
|
|||||||
// SIG(0)
|
|
||||||
//
|
|
||||||
// From RFC 2931:
|
|
||||||
//
|
|
||||||
// SIG(0) provides protection for DNS transactions and requests ....
|
|
||||||
// ... protection for glue records, DNS requests, protection for message headers
|
|
||||||
// on requests and responses, and protection of the overall integrity of a response.
|
|
||||||
//
|
|
||||||
// It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
|
|
||||||
// secret approach in TSIG.
|
|
||||||
// Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
|
|
||||||
// RSASHA512.
|
|
||||||
//
|
|
||||||
// Signing subsequent messages in multi-message sessions is not implemented.
|
|
||||||
//
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -29,7 +13,7 @@ import (
|
|||||||
// Sign signs a dns.Msg. It fills the signature with the appropriate data.
|
// Sign signs a dns.Msg. It fills the signature with the appropriate data.
|
||||||
// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
|
// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
|
||||||
// and Expiration set.
|
// and Expiration set.
|
||||||
func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
|
func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
||||||
if k == nil {
|
if k == nil {
|
||||||
return nil, ErrPrivKey
|
return nil, ErrPrivKey
|
||||||
}
|
}
|
||||||
@@ -57,56 +41,26 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf = buf[:off:cap(buf)]
|
buf = buf[:off:cap(buf)]
|
||||||
var hash crypto.Hash
|
|
||||||
var intlen int
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
switch rr.Algorithm {
|
if !ok {
|
||||||
case DSA, RSASHA1:
|
|
||||||
hash = crypto.SHA1
|
|
||||||
case RSASHA256, ECDSAP256SHA256:
|
|
||||||
hash = crypto.SHA256
|
|
||||||
intlen = 32
|
|
||||||
case ECDSAP384SHA384:
|
|
||||||
hash = crypto.SHA384
|
|
||||||
intlen = 48
|
|
||||||
case RSASHA512:
|
|
||||||
hash = crypto.SHA512
|
|
||||||
default:
|
|
||||||
return nil, ErrAlg
|
return nil, ErrAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
hasher := hash.New()
|
hasher := hash.New()
|
||||||
// Write SIG rdata
|
// Write SIG rdata
|
||||||
hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
|
hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
|
||||||
// Write message
|
// Write message
|
||||||
hasher.Write(buf[:len(mbuf)])
|
hasher.Write(buf[:len(mbuf)])
|
||||||
hashed := hasher.Sum(nil)
|
|
||||||
|
|
||||||
var sig []byte
|
signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
|
||||||
switch p := k.(type) {
|
if err != nil {
|
||||||
case *dsa.PrivateKey:
|
return nil, err
|
||||||
t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
|
|
||||||
r1, s1, err := dsa.Sign(rand.Reader, p, hashed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sig = append(sig, byte(t))
|
|
||||||
sig = append(sig, intToBytes(r1, 20)...)
|
|
||||||
sig = append(sig, intToBytes(s1, 20)...)
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
sig, err = rsa.SignPKCS1v15(rand.Reader, p, hash, hashed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
r1, s1, err := ecdsa.Sign(rand.Reader, p, hashed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sig = intToBytes(r1, intlen)
|
|
||||||
sig = append(sig, intToBytes(s1, intlen)...)
|
|
||||||
default:
|
|
||||||
return nil, ErrAlg
|
|
||||||
}
|
}
|
||||||
rr.Signature = toBase64(sig)
|
|
||||||
|
rr.Signature = toBase64(signature)
|
||||||
|
sig := string(signature)
|
||||||
|
|
||||||
buf = append(buf, sig...)
|
buf = append(buf, sig...)
|
||||||
if len(buf) > int(^uint16(0)) {
|
if len(buf) > int(^uint16(0)) {
|
||||||
return nil, ErrBuf
|
return nil, ErrBuf
|
||||||
@@ -118,7 +72,7 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
|
|||||||
buf[rdoff], buf[rdoff+1] = packUint16(rdlen)
|
buf[rdoff], buf[rdoff+1] = packUint16(rdlen)
|
||||||
// Adjust additional count
|
// Adjust additional count
|
||||||
adc, _ := unpackUint16(buf, 10)
|
adc, _ := unpackUint16(buf, 10)
|
||||||
adc += 1
|
adc++
|
||||||
buf[10], buf[11] = packUint16(adc)
|
buf[10], buf[11] = packUint16(adc)
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
@@ -246,7 +200,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||||||
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
|
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
|
||||||
}
|
}
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
pk := k.publicKeyCurve()
|
pk := k.publicKeyECDSA()
|
||||||
r := big.NewInt(0)
|
r := big.NewInt(0)
|
||||||
r.SetBytes(sig[:len(sig)/2])
|
r.SetBytes(sig[:len(sig)/2])
|
||||||
s := big.NewInt(0)
|
s := big.NewInt(0)
|
||||||
|
|||||||
8
vendor/github.com/miekg/dns/tlsa.go
generated
vendored
8
vendor/github.com/miekg/dns/tlsa.go
generated
vendored
@@ -25,7 +25,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st
|
|||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
switch selector {
|
switch selector {
|
||||||
case 0:
|
case 0:
|
||||||
return hex.EncodeToString(cert.Raw), nil
|
io.WriteString(h, string(cert.Raw))
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
case 1:
|
case 1:
|
||||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
@@ -34,7 +35,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st
|
|||||||
h := sha512.New()
|
h := sha512.New()
|
||||||
switch selector {
|
switch selector {
|
||||||
case 0:
|
case 0:
|
||||||
return hex.EncodeToString(cert.Raw), nil
|
io.WriteString(h, string(cert.Raw))
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
case 1:
|
case 1:
|
||||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
@@ -80,5 +82,5 @@ func TLSAName(name, service, network string) (string, error) {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
return "", e
|
return "", e
|
||||||
}
|
}
|
||||||
return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil
|
return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil
|
||||||
}
|
}
|
||||||
|
|||||||
78
vendor/github.com/miekg/dns/tsig.go
generated
vendored
78
vendor/github.com/miekg/dns/tsig.go
generated
vendored
@@ -1,56 +1,3 @@
|
|||||||
// TRANSACTION SIGNATURE
|
|
||||||
//
|
|
||||||
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
|
|
||||||
// The supported algorithms include: HmacMD5, HmacSHA1 and HmacSHA256.
|
|
||||||
//
|
|
||||||
// Basic use pattern when querying with a TSIG name "axfr." (note that these key names
|
|
||||||
// must be fully qualified - as they are domain names) and the base64 secret
|
|
||||||
// "so6ZGir4GPAqINNh9U5c3A==":
|
|
||||||
//
|
|
||||||
// c := new(dns.Client)
|
|
||||||
// c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
|
||||||
// m := new(dns.Msg)
|
|
||||||
// m.SetQuestion("miek.nl.", dns.TypeMX)
|
|
||||||
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
|
||||||
// ...
|
|
||||||
// // When sending the TSIG RR is calculated and filled in before sending
|
|
||||||
//
|
|
||||||
// When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
|
|
||||||
// TSIG, this is the basic use pattern. In this example we request an AXFR for
|
|
||||||
// miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
|
|
||||||
// and using the server 176.58.119.54:
|
|
||||||
//
|
|
||||||
// t := new(dns.Transfer)
|
|
||||||
// m := new(dns.Msg)
|
|
||||||
// t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
|
||||||
// m.SetAxfr("miek.nl.")
|
|
||||||
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
|
||||||
// c, err := t.In(m, "176.58.119.54:53")
|
|
||||||
// for r := range c { /* r.RR */ }
|
|
||||||
//
|
|
||||||
// You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
|
|
||||||
// If something is not correct an error is returned.
|
|
||||||
//
|
|
||||||
// Basic use pattern validating and replying to a message that has TSIG set.
|
|
||||||
//
|
|
||||||
// server := &dns.Server{Addr: ":53", Net: "udp"}
|
|
||||||
// server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
|
||||||
// go server.ListenAndServe()
|
|
||||||
// dns.HandleFunc(".", handleRequest)
|
|
||||||
//
|
|
||||||
// func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
|
||||||
// m := new(Msg)
|
|
||||||
// m.SetReply(r)
|
|
||||||
// if r.IsTsig() {
|
|
||||||
// if w.TsigStatus() == nil {
|
|
||||||
// // *Msg r has an TSIG record and it was validated
|
|
||||||
// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
|
||||||
// } else {
|
|
||||||
// // *Msg r has an TSIG records and it was not valided
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// w.WriteMsg(m)
|
|
||||||
// }
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -58,6 +5,7 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
@@ -71,8 +19,11 @@ const (
|
|||||||
HmacMD5 = "hmac-md5.sig-alg.reg.int."
|
HmacMD5 = "hmac-md5.sig-alg.reg.int."
|
||||||
HmacSHA1 = "hmac-sha1."
|
HmacSHA1 = "hmac-sha1."
|
||||||
HmacSHA256 = "hmac-sha256."
|
HmacSHA256 = "hmac-sha256."
|
||||||
|
HmacSHA512 = "hmac-sha512."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TSIG is the RR the holds the transaction signature of a message.
|
||||||
|
// See RFC 2845 and RFC 4635.
|
||||||
type TSIG struct {
|
type TSIG struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
Algorithm string `dns:"domain-name"`
|
Algorithm string `dns:"domain-name"`
|
||||||
@@ -86,10 +37,6 @@ type TSIG struct {
|
|||||||
OtherData string `dns:"size-hex"`
|
OtherData string `dns:"size-hex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *TSIG) Header() *RR_Header {
|
|
||||||
return &rr.Hdr
|
|
||||||
}
|
|
||||||
|
|
||||||
// TSIG has no official presentation format, but this will suffice.
|
// TSIG has no official presentation format, but this will suffice.
|
||||||
|
|
||||||
func (rr *TSIG) String() string {
|
func (rr *TSIG) String() string {
|
||||||
@@ -107,15 +54,6 @@ func (rr *TSIG) String() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *TSIG) len() int {
|
|
||||||
return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
|
|
||||||
4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *TSIG) copy() RR {
|
|
||||||
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following values must be put in wireformat, so that the MAC can be calculated.
|
// The following values must be put in wireformat, so that the MAC can be calculated.
|
||||||
// RFC 2845, section 3.4.2. TSIG Variables.
|
// RFC 2845, section 3.4.2. TSIG Variables.
|
||||||
type tsigWireFmt struct {
|
type tsigWireFmt struct {
|
||||||
@@ -174,13 +112,15 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
|
|||||||
|
|
||||||
t := new(TSIG)
|
t := new(TSIG)
|
||||||
var h hash.Hash
|
var h hash.Hash
|
||||||
switch rr.Algorithm {
|
switch strings.ToLower(rr.Algorithm) {
|
||||||
case HmacMD5:
|
case HmacMD5:
|
||||||
h = hmac.New(md5.New, []byte(rawsecret))
|
h = hmac.New(md5.New, []byte(rawsecret))
|
||||||
case HmacSHA1:
|
case HmacSHA1:
|
||||||
h = hmac.New(sha1.New, []byte(rawsecret))
|
h = hmac.New(sha1.New, []byte(rawsecret))
|
||||||
case HmacSHA256:
|
case HmacSHA256:
|
||||||
h = hmac.New(sha256.New, []byte(rawsecret))
|
h = hmac.New(sha256.New, []byte(rawsecret))
|
||||||
|
case HmacSHA512:
|
||||||
|
h = hmac.New(sha512.New, []byte(rawsecret))
|
||||||
default:
|
default:
|
||||||
return nil, "", ErrKeyAlg
|
return nil, "", ErrKeyAlg
|
||||||
}
|
}
|
||||||
@@ -238,13 +178,15 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var h hash.Hash
|
var h hash.Hash
|
||||||
switch tsig.Algorithm {
|
switch strings.ToLower(tsig.Algorithm) {
|
||||||
case HmacMD5:
|
case HmacMD5:
|
||||||
h = hmac.New(md5.New, rawsecret)
|
h = hmac.New(md5.New, rawsecret)
|
||||||
case HmacSHA1:
|
case HmacSHA1:
|
||||||
h = hmac.New(sha1.New, rawsecret)
|
h = hmac.New(sha1.New, rawsecret)
|
||||||
case HmacSHA256:
|
case HmacSHA256:
|
||||||
h = hmac.New(sha256.New, rawsecret)
|
h = hmac.New(sha256.New, rawsecret)
|
||||||
|
case HmacSHA512:
|
||||||
|
h = hmac.New(sha512.New, rawsecret)
|
||||||
default:
|
default:
|
||||||
return ErrKeyAlg
|
return ErrKeyAlg
|
||||||
}
|
}
|
||||||
|
|||||||
643
vendor/github.com/miekg/dns/types.go
generated
vendored
643
vendor/github.com/miekg/dns/types.go
generated
vendored
File diff suppressed because it is too large
Load Diff
266
vendor/github.com/miekg/dns/types_generate.go
generated
vendored
Normal file
266
vendor/github.com/miekg/dns/types_generate.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
//+build ignore
|
||||||
|
|
||||||
|
// types_generate.go is meant to run with go generate. It will use
|
||||||
|
// go/{importer,types} to track down all the RR struct types. Then for each type
|
||||||
|
// it will generate conversion tables (TypeToRR and TypeToString) and banal
|
||||||
|
// methods (len, Header, copy) based on the struct tags. The generated source is
|
||||||
|
// written to ztypes.go, and is meant to be checked into git.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"go/importer"
|
||||||
|
"go/types"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var skipLen = map[string]struct{}{
|
||||||
|
"NSEC": {},
|
||||||
|
"NSEC3": {},
|
||||||
|
"OPT": {},
|
||||||
|
"WKS": {},
|
||||||
|
"IPSECKEY": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
var packageHdr = `
|
||||||
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
var TypeToRR = template.Must(template.New("TypeToRR").Parse(`
|
||||||
|
// TypeToRR is a map of constructors for each RR type.
|
||||||
|
var TypeToRR = map[uint16]func() RR{
|
||||||
|
{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) },
|
||||||
|
{{end}}{{end}} }
|
||||||
|
|
||||||
|
`))
|
||||||
|
|
||||||
|
var typeToString = template.Must(template.New("typeToString").Parse(`
|
||||||
|
// TypeToString is a map of strings for each RR type.
|
||||||
|
var TypeToString = map[uint16]string{
|
||||||
|
{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}",
|
||||||
|
{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR",
|
||||||
|
}
|
||||||
|
|
||||||
|
`))
|
||||||
|
|
||||||
|
var headerFunc = template.Must(template.New("headerFunc").Parse(`
|
||||||
|
// Header() functions
|
||||||
|
{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
`))
|
||||||
|
|
||||||
|
// getTypeStruct will take a type and the package scope, and return the
|
||||||
|
// (innermost) struct if the type is considered a RR type (currently defined as
|
||||||
|
// those structs beginning with a RR_Header, could be redefined as implementing
|
||||||
|
// the RR interface). The bool return value indicates if embedded structs were
|
||||||
|
// resolved.
|
||||||
|
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
|
||||||
|
st, ok := t.Underlying().(*types.Struct)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
|
||||||
|
return st, false
|
||||||
|
}
|
||||||
|
if st.Field(0).Anonymous() {
|
||||||
|
st, _ := getTypeStruct(st.Field(0).Type(), scope)
|
||||||
|
return st, true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Import and type-check the package
|
||||||
|
pkg, err := importer.Default().Import("github.com/miekg/dns")
|
||||||
|
fatalIfErr(err)
|
||||||
|
scope := pkg.Scope()
|
||||||
|
|
||||||
|
// Collect constants like TypeX
|
||||||
|
var numberedTypes []string
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
o := scope.Lookup(name)
|
||||||
|
if o == nil || !o.Exported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b, ok := o.Type().(*types.Basic)
|
||||||
|
if !ok || b.Kind() != types.Uint16 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(o.Name(), "Type") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := strings.TrimPrefix(o.Name(), "Type")
|
||||||
|
if name == "PrivateRR" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
numberedTypes = append(numberedTypes, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect actual types (*X)
|
||||||
|
var namedTypes []string
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
o := scope.Lookup(name)
|
||||||
|
if o == nil || !o.Exported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if name == "PrivateRR" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if corresponding TypeX exists
|
||||||
|
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
|
||||||
|
log.Fatalf("Constant Type%s does not exist.", o.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
namedTypes = append(namedTypes, o.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
b.WriteString(packageHdr)
|
||||||
|
|
||||||
|
// Generate TypeToRR
|
||||||
|
fatalIfErr(TypeToRR.Execute(b, namedTypes))
|
||||||
|
|
||||||
|
// Generate typeToString
|
||||||
|
fatalIfErr(typeToString.Execute(b, numberedTypes))
|
||||||
|
|
||||||
|
// Generate headerFunc
|
||||||
|
fatalIfErr(headerFunc.Execute(b, namedTypes))
|
||||||
|
|
||||||
|
// Generate len()
|
||||||
|
fmt.Fprint(b, "// len() functions\n")
|
||||||
|
for _, name := range namedTypes {
|
||||||
|
if _, ok := skipLen[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
o := scope.Lookup(name)
|
||||||
|
st, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||||
|
if isEmbedded {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
|
||||||
|
fmt.Fprintf(b, "l := rr.Hdr.len()\n")
|
||||||
|
for i := 1; i < st.NumFields(); i++ {
|
||||||
|
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
|
||||||
|
|
||||||
|
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||||
|
switch st.Tag(i) {
|
||||||
|
case `dns:"-"`:
|
||||||
|
// ignored
|
||||||
|
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
|
||||||
|
o("for _, x := range rr.%s { l += len(x) + 1 }\n")
|
||||||
|
default:
|
||||||
|
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch st.Tag(i) {
|
||||||
|
case `dns:"-"`:
|
||||||
|
// ignored
|
||||||
|
case `dns:"cdomain-name"`, `dns:"domain-name"`:
|
||||||
|
o("l += len(rr.%s) + 1\n")
|
||||||
|
case `dns:"octet"`:
|
||||||
|
o("l += len(rr.%s)\n")
|
||||||
|
case `dns:"base64"`:
|
||||||
|
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
|
||||||
|
case `dns:"size-hex"`, `dns:"hex"`:
|
||||||
|
o("l += len(rr.%s)/2 + 1\n")
|
||||||
|
case `dns:"a"`:
|
||||||
|
o("l += net.IPv4len // %s\n")
|
||||||
|
case `dns:"aaaa"`:
|
||||||
|
o("l += net.IPv6len // %s\n")
|
||||||
|
case `dns:"txt"`:
|
||||||
|
o("for _, t := range rr.%s { l += len(t) + 1 }\n")
|
||||||
|
case `dns:"uint48"`:
|
||||||
|
o("l += 6 // %s\n")
|
||||||
|
case "":
|
||||||
|
switch st.Field(i).Type().(*types.Basic).Kind() {
|
||||||
|
case types.Uint8:
|
||||||
|
o("l += 1 // %s\n")
|
||||||
|
case types.Uint16:
|
||||||
|
o("l += 2 // %s\n")
|
||||||
|
case types.Uint32:
|
||||||
|
o("l += 4 // %s\n")
|
||||||
|
case types.Uint64:
|
||||||
|
o("l += 8 // %s\n")
|
||||||
|
case types.String:
|
||||||
|
o("l += len(rr.%s) + 1\n")
|
||||||
|
default:
|
||||||
|
log.Fatalln(name, st.Field(i).Name())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "return l }\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate copy()
|
||||||
|
fmt.Fprint(b, "// copy() functions\n")
|
||||||
|
for _, name := range namedTypes {
|
||||||
|
o := scope.Lookup(name)
|
||||||
|
st, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||||
|
if isEmbedded {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
|
||||||
|
fields := []string{"*rr.Hdr.copyHeader()"}
|
||||||
|
for i := 1; i < st.NumFields(); i++ {
|
||||||
|
f := st.Field(i).Name()
|
||||||
|
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||||
|
t := sl.Underlying().String()
|
||||||
|
t = strings.TrimPrefix(t, "[]")
|
||||||
|
t = strings.TrimPrefix(t, "github.com/miekg/dns.")
|
||||||
|
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
|
||||||
|
f, t, f, f, f)
|
||||||
|
fields = append(fields, f)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if st.Field(i).Type().String() == "net.IP" {
|
||||||
|
fields = append(fields, "copyIP(rr."+f+")")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fields = append(fields, "rr."+f)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ","))
|
||||||
|
fmt.Fprintf(b, "}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// gofmt
|
||||||
|
res, err := format.Source(b.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
b.WriteTo(os.Stderr)
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write result
|
||||||
|
f, err := os.Create("ztypes.go")
|
||||||
|
fatalIfErr(err)
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fatalIfErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/github.com/miekg/dns/udp.go
generated
vendored
19
vendor/github.com/miekg/dns/udp.go
generated
vendored
@@ -1,4 +1,4 @@
|
|||||||
// +build !windows
|
// +build !windows,!plan9
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
@@ -7,12 +7,15 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sessionUDP struct {
|
// SessionUDP holds the remote address and the associated
|
||||||
|
// out-of-band data.
|
||||||
|
type SessionUDP struct {
|
||||||
raddr *net.UDPAddr
|
raddr *net.UDPAddr
|
||||||
context []byte
|
context []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
// RemoteAddr returns the remote network address.
|
||||||
|
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||||
|
|
||||||
// setUDPSocketOptions sets the UDP socket options.
|
// setUDPSocketOptions sets the UDP socket options.
|
||||||
// This function is implemented on a per platform basis. See udp_*.go for more details
|
// This function is implemented on a per platform basis. See udp_*.go for more details
|
||||||
@@ -37,19 +40,19 @@ func setUDPSocketOptions(conn *net.UDPConn) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||||
// net.UDPAddr.
|
// net.UDPAddr.
|
||||||
func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
oob := make([]byte, 40)
|
oob := make([]byte, 40)
|
||||||
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, nil, err
|
return n, nil, err
|
||||||
}
|
}
|
||||||
return n, &sessionUDP{raddr, oob[:oobn]}, err
|
return n, &SessionUDP{raddr, oob[:oobn]}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.
|
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||||
func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) {
|
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||||
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
|
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|||||||
10
vendor/github.com/miekg/dns/udp_linux.go
generated
vendored
10
vendor/github.com/miekg/dns/udp_linux.go
generated
vendored
@@ -24,6 +24,12 @@ func setUDPSocketOptions4(conn *net.UDPConn) error {
|
|||||||
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
|
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Calling File() above results in the connection becoming blocking, we must fix that.
|
||||||
|
// See https://github.com/miekg/dns/issues/279
|
||||||
|
err = syscall.SetNonblock(int(file.Fd()), true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +42,10 @@ func setUDPSocketOptions6(conn *net.UDPConn) error {
|
|||||||
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
|
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = syscall.SetNonblock(int(file.Fd()), true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/miekg/dns/udp_other.go
generated
vendored
2
vendor/github.com/miekg/dns/udp_other.go
generated
vendored
@@ -1,4 +1,4 @@
|
|||||||
// +build !linux
|
// +build !linux,!plan9
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
|||||||
34
vendor/github.com/miekg/dns/udp_plan9.go
generated
vendored
Normal file
34
vendor/github.com/miekg/dns/udp_plan9.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
|
||||||
|
|
||||||
|
// SessionUDP holds the remote address and the associated
|
||||||
|
// out-of-band data.
|
||||||
|
type SessionUDP struct {
|
||||||
|
raddr *net.UDPAddr
|
||||||
|
context []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteAddr returns the remote network address.
|
||||||
|
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||||
|
|
||||||
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||||
|
// net.UDPAddr.
|
||||||
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
|
oob := make([]byte, 40)
|
||||||
|
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||||
|
if err != nil {
|
||||||
|
return n, nil, err
|
||||||
|
}
|
||||||
|
return n, &SessionUDP{raddr, oob[:oobn]}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||||
|
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||||
|
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
14
vendor/github.com/miekg/dns/udp_windows.go
generated
vendored
14
vendor/github.com/miekg/dns/udp_windows.go
generated
vendored
@@ -4,28 +4,28 @@ package dns
|
|||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
||||||
type sessionUDP struct {
|
type SessionUDP struct {
|
||||||
raddr *net.UDPAddr
|
raddr *net.UDPAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||||
// net.UDPAddr.
|
// net.UDPAddr.
|
||||||
func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
n, raddr, err := conn.ReadFrom(b)
|
n, raddr, err := conn.ReadFrom(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, nil, err
|
return n, nil, err
|
||||||
}
|
}
|
||||||
session := &sessionUDP{raddr.(*net.UDPAddr)}
|
session := &SessionUDP{raddr.(*net.UDPAddr)}
|
||||||
return n, session, err
|
return n, session, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.
|
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||||
func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) {
|
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||||
n, err := conn.WriteTo(b, session.raddr)
|
n, err := conn.WriteTo(b, session.raddr)
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||||
|
|
||||||
// setUDPSocketOptions sets the UDP socket options.
|
// setUDPSocketOptions sets the UDP socket options.
|
||||||
// This function is implemented on a per platform basis. See udp_*.go for more details
|
// This function is implemented on a per platform basis. See udp_*.go for more details
|
||||||
|
|||||||
130
vendor/github.com/miekg/dns/update.go
generated
vendored
130
vendor/github.com/miekg/dns/update.go
generated
vendored
@@ -1,55 +1,24 @@
|
|||||||
// DYNAMIC UPDATES
|
|
||||||
//
|
|
||||||
// Dynamic updates reuses the DNS message format, but renames three of
|
|
||||||
// the sections. Question is Zone, Answer is Prerequisite, Authority is
|
|
||||||
// Update, only the Additional is not renamed. See RFC 2136 for the gory details.
|
|
||||||
//
|
|
||||||
// You can set a rather complex set of rules for the existence of absence of
|
|
||||||
// certain resource records or names in a zone to specify if resource records
|
|
||||||
// should be added or removed. The table from RFC 2136 supplemented with the Go
|
|
||||||
// DNS function shows which functions exist to specify the prerequisites.
|
|
||||||
//
|
|
||||||
// 3.2.4 - Table Of Metavalues Used In Prerequisite Section
|
|
||||||
//
|
|
||||||
// CLASS TYPE RDATA Meaning Function
|
|
||||||
// --------------------------------------------------------------
|
|
||||||
// ANY ANY empty Name is in use dns.NameUsed
|
|
||||||
// ANY rrset empty RRset exists (value indep) dns.RRsetUsed
|
|
||||||
// NONE ANY empty Name is not in use dns.NameNotUsed
|
|
||||||
// NONE rrset empty RRset does not exist dns.RRsetNotUsed
|
|
||||||
// zone rrset rr RRset exists (value dep) dns.Used
|
|
||||||
//
|
|
||||||
// The prerequisite section can also be left empty.
|
|
||||||
// If you have decided on the prerequisites you can tell what RRs should
|
|
||||||
// be added or deleted. The next table shows the options you have and
|
|
||||||
// what functions to call.
|
|
||||||
//
|
|
||||||
// 3.4.2.6 - Table Of Metavalues Used In Update Section
|
|
||||||
//
|
|
||||||
// CLASS TYPE RDATA Meaning Function
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
// ANY ANY empty Delete all RRsets from name dns.RemoveName
|
|
||||||
// ANY rrset empty Delete an RRset dns.RemoveRRset
|
|
||||||
// NONE rrset rr Delete an RR from RRset dns.Remove
|
|
||||||
// zone rrset rr Add to an RRset dns.Insert
|
|
||||||
//
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
// NameUsed sets the RRs in the prereq section to
|
// NameUsed sets the RRs in the prereq section to
|
||||||
// "Name is in use" RRs. RFC 2136 section 2.4.4.
|
// "Name is in use" RRs. RFC 2136 section 2.4.4.
|
||||||
func (u *Msg) NameUsed(rr []RR) {
|
func (u *Msg) NameUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
|
}
|
||||||
|
for _, r := range rr {
|
||||||
|
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameNotUsed sets the RRs in the prereq section to
|
// NameNotUsed sets the RRs in the prereq section to
|
||||||
// "Name is in not use" RRs. RFC 2136 section 2.4.5.
|
// "Name is in not use" RRs. RFC 2136 section 2.4.5.
|
||||||
func (u *Msg) NameNotUsed(rr []RR) {
|
func (u *Msg) NameNotUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}
|
}
|
||||||
|
for _, r := range rr {
|
||||||
|
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,34 +28,34 @@ func (u *Msg) Used(rr []RR) {
|
|||||||
if len(u.Question) == 0 {
|
if len(u.Question) == 0 {
|
||||||
panic("dns: empty question section")
|
panic("dns: empty question section")
|
||||||
}
|
}
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = r
|
}
|
||||||
u.Answer[i].Header().Class = u.Question[0].Qclass
|
for _, r := range rr {
|
||||||
|
r.Header().Class = u.Question[0].Qclass
|
||||||
|
u.Answer = append(u.Answer, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RRsetUsed sets the RRs in the prereq section to
|
// RRsetUsed sets the RRs in the prereq section to
|
||||||
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
|
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
|
||||||
func (u *Msg) RRsetUsed(rr []RR) {
|
func (u *Msg) RRsetUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = r
|
}
|
||||||
u.Answer[i].Header().Class = ClassANY
|
for _, r := range rr {
|
||||||
u.Answer[i].Header().Ttl = 0
|
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
|
||||||
u.Answer[i].Header().Rdlength = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RRsetNotUsed sets the RRs in the prereq section to
|
// RRsetNotUsed sets the RRs in the prereq section to
|
||||||
// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
|
// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
|
||||||
func (u *Msg) RRsetNotUsed(rr []RR) {
|
func (u *Msg) RRsetNotUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = r
|
}
|
||||||
u.Answer[i].Header().Class = ClassNONE
|
for _, r := range rr {
|
||||||
u.Answer[i].Header().Rdlength = 0
|
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
|
||||||
u.Answer[i].Header().Ttl = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,44 +64,43 @@ func (u *Msg) Insert(rr []RR) {
|
|||||||
if len(u.Question) == 0 {
|
if len(u.Question) == 0 {
|
||||||
panic("dns: empty question section")
|
panic("dns: empty question section")
|
||||||
}
|
}
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = r
|
}
|
||||||
u.Ns[i].Header().Class = u.Question[0].Qclass
|
for _, r := range rr {
|
||||||
|
r.Header().Class = u.Question[0].Qclass
|
||||||
|
u.Ns = append(u.Ns, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
|
// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
|
||||||
func (u *Msg) RemoveRRset(rr []RR) {
|
func (u *Msg) RemoveRRset(rr []RR) {
|
||||||
m := make(map[RR_Header]struct{})
|
if u.Ns == nil {
|
||||||
u.Ns = make([]RR, 0, len(rr))
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
|
}
|
||||||
for _, r := range rr {
|
for _, r := range rr {
|
||||||
h := *r.Header().copyHeader()
|
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
|
||||||
h.Class = ClassANY
|
|
||||||
h.Ttl = 0
|
|
||||||
h.Rdlength = 0
|
|
||||||
if _, ok := m[h]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m[h] = struct{}{}
|
|
||||||
u.Ns = append(u.Ns, &ANY{h})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
|
// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
|
||||||
func (u *Msg) RemoveName(rr []RR) {
|
func (u *Msg) RemoveName(rr []RR) {
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
|
}
|
||||||
|
for _, r := range rr {
|
||||||
|
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4
|
// Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
|
||||||
func (u *Msg) Remove(rr []RR) {
|
func (u *Msg) Remove(rr []RR) {
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = r
|
}
|
||||||
u.Ns[i].Header().Class = ClassNONE
|
for _, r := range rr {
|
||||||
u.Ns[i].Header().Ttl = 0
|
r.Header().Class = ClassNONE
|
||||||
|
r.Header().Ttl = 0
|
||||||
|
u.Ns = append(u.Ns, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
vendor/github.com/miekg/dns/xfr.go
generated
vendored
54
vendor/github.com/miekg/dns/xfr.go
generated
vendored
@@ -13,9 +13,9 @@ type Envelope struct {
|
|||||||
// A Transfer defines parameters that are used during a zone transfer.
|
// A Transfer defines parameters that are used during a zone transfer.
|
||||||
type Transfer struct {
|
type Transfer struct {
|
||||||
*Conn
|
*Conn
|
||||||
DialTimeout time.Duration // net.DialTimeout (ns), defaults to 2 * 1e9
|
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
|
||||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections (ns), defaults to 2 * 1e9
|
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
|
||||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections (ns), defaults to 2 * 1e9
|
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
|
||||||
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
||||||
tsigTimersOnly bool
|
tsigTimersOnly bool
|
||||||
}
|
}
|
||||||
@@ -23,14 +23,26 @@ type Transfer struct {
|
|||||||
// Think we need to away to stop the transfer
|
// Think we need to away to stop the transfer
|
||||||
|
|
||||||
// In performs an incoming transfer with the server in a.
|
// In performs an incoming transfer with the server in a.
|
||||||
|
// If you would like to set the source IP, or some other attribute
|
||||||
|
// of a Dialer for a Transfer, you can do so by specifying the attributes
|
||||||
|
// in the Transfer.Conn:
|
||||||
|
//
|
||||||
|
// d := net.Dialer{LocalAddr: transfer_source}
|
||||||
|
// con, err := d.Dial("tcp", master)
|
||||||
|
// dnscon := &dns.Conn{Conn:con}
|
||||||
|
// transfer = &dns.Transfer{Conn: dnscon}
|
||||||
|
// channel, err := transfer.In(message, master)
|
||||||
|
//
|
||||||
func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
|
func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
|
||||||
timeout := dnsTimeout
|
timeout := dnsTimeout
|
||||||
if t.DialTimeout != 0 {
|
if t.DialTimeout != 0 {
|
||||||
timeout = t.DialTimeout
|
timeout = t.DialTimeout
|
||||||
}
|
}
|
||||||
t.Conn, err = DialTimeout("tcp", a, timeout)
|
if t.Conn == nil {
|
||||||
if err != nil {
|
t.Conn, err = DialTimeout("tcp", a, timeout)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := t.WriteMsg(q); err != nil {
|
if err := t.WriteMsg(q); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -91,7 +103,6 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
|
|||||||
c <- &Envelope{in.Answer, nil}
|
c <- &Envelope{in.Answer, nil}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
||||||
@@ -107,7 +118,7 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
|||||||
t.SetReadDeadline(time.Now().Add(timeout))
|
t.SetReadDeadline(time.Now().Add(timeout))
|
||||||
in, err := t.ReadMsg()
|
in, err := t.ReadMsg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c <- &Envelope{in.Answer, err}
|
c <- &Envelope{nil, err}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if id != in.Id {
|
if id != in.Id {
|
||||||
@@ -160,22 +171,18 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
|||||||
// The server is responsible for sending the correct sequence of RRs through the
|
// The server is responsible for sending the correct sequence of RRs through the
|
||||||
// channel ch.
|
// channel ch.
|
||||||
func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
|
func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
|
||||||
r := new(Msg)
|
for x := range ch {
|
||||||
// Compress?
|
r := new(Msg)
|
||||||
r.SetReply(q)
|
// Compress?
|
||||||
r.Authoritative = true
|
r.SetReply(q)
|
||||||
|
r.Authoritative = true
|
||||||
go func() {
|
// assume it fits TODO(miek): fix
|
||||||
for x := range ch {
|
r.Answer = append(r.Answer, x.RR...)
|
||||||
// assume it fits TODO(miek): fix
|
if err := w.WriteMsg(r); err != nil {
|
||||||
r.Answer = append(r.Answer, x.RR...)
|
return err
|
||||||
if err := w.WriteMsg(r); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
w.TsigTimersOnly(true)
|
}
|
||||||
r.Answer = nil
|
w.TsigTimersOnly(true)
|
||||||
}()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +204,7 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
|
|||||||
}
|
}
|
||||||
// Need to work on the original message p, as that was used to calculate the tsig.
|
// Need to work on the original message p, as that was used to calculate the tsig.
|
||||||
err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
|
err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
|
||||||
|
t.tsigRequestMAC = ts.MAC
|
||||||
}
|
}
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|||||||
33
vendor/github.com/miekg/dns/zgenerate.go
generated
vendored
33
vendor/github.com/miekg/dns/zgenerate.go
generated
vendored
@@ -1,6 +1,7 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -14,7 +15,7 @@ import (
|
|||||||
// * [[ttl][class]]
|
// * [[ttl][class]]
|
||||||
// * type
|
// * type
|
||||||
// * rhs (rdata)
|
// * rhs (rdata)
|
||||||
// But we are lazy here, only the range is parsed *all* occurences
|
// But we are lazy here, only the range is parsed *all* occurrences
|
||||||
// of $ after that are interpreted.
|
// of $ after that are interpreted.
|
||||||
// Any error are returned as a string value, the empty string signals
|
// Any error are returned as a string value, the empty string signals
|
||||||
// "no error".
|
// "no error".
|
||||||
@@ -24,13 +25,13 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
|
|||||||
if i+1 == len(l.token) {
|
if i+1 == len(l.token) {
|
||||||
return "bad step in $GENERATE range"
|
return "bad step in $GENERATE range"
|
||||||
}
|
}
|
||||||
if s, e := strconv.Atoi(l.token[i+1:]); e != nil {
|
if s, e := strconv.Atoi(l.token[i+1:]); e == nil {
|
||||||
return "bad step in $GENERATE range"
|
|
||||||
} else {
|
|
||||||
if s < 0 {
|
if s < 0 {
|
||||||
return "bad step in $GENERATE range"
|
return "bad step in $GENERATE range"
|
||||||
}
|
}
|
||||||
step = s
|
step = s
|
||||||
|
} else {
|
||||||
|
return "bad step in $GENERATE range"
|
||||||
}
|
}
|
||||||
l.token = l.token[:i]
|
l.token = l.token[:i]
|
||||||
}
|
}
|
||||||
@@ -46,7 +47,7 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "bad stop in $GENERATE range"
|
return "bad stop in $GENERATE range"
|
||||||
}
|
}
|
||||||
if end < 0 || start < 0 || end <= start {
|
if end < 0 || start < 0 || end < start {
|
||||||
return "bad range in $GENERATE range"
|
return "bad range in $GENERATE range"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,14 +56,14 @@ func generate(l lex, c chan lex, t chan *Token, o string) string {
|
|||||||
s := ""
|
s := ""
|
||||||
BuildRR:
|
BuildRR:
|
||||||
l = <-c
|
l = <-c
|
||||||
if l.value != _NEWLINE && l.value != _EOF {
|
if l.value != zNewline && l.value != zEOF {
|
||||||
s += l.token
|
s += l.token
|
||||||
goto BuildRR
|
goto BuildRR
|
||||||
}
|
}
|
||||||
for i := start; i <= end; i += step {
|
for i := start; i <= end; i += step {
|
||||||
var (
|
var (
|
||||||
escape bool
|
escape bool
|
||||||
dom string
|
dom bytes.Buffer
|
||||||
mod string
|
mod string
|
||||||
err string
|
err string
|
||||||
offset int
|
offset int
|
||||||
@@ -72,7 +73,7 @@ BuildRR:
|
|||||||
switch s[j] {
|
switch s[j] {
|
||||||
case '\\':
|
case '\\':
|
||||||
if escape {
|
if escape {
|
||||||
dom += "\\"
|
dom.WriteByte('\\')
|
||||||
escape = false
|
escape = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -81,17 +82,17 @@ BuildRR:
|
|||||||
mod = "%d"
|
mod = "%d"
|
||||||
offset = 0
|
offset = 0
|
||||||
if escape {
|
if escape {
|
||||||
dom += "$"
|
dom.WriteByte('$')
|
||||||
escape = false
|
escape = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
escape = false
|
escape = false
|
||||||
if j+1 >= len(s) { // End of the string
|
if j+1 >= len(s) { // End of the string
|
||||||
dom += fmt.Sprintf(mod, i+offset)
|
dom.WriteString(fmt.Sprintf(mod, i+offset))
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
if s[j+1] == '$' {
|
if s[j+1] == '$' {
|
||||||
dom += "$"
|
dom.WriteByte('$')
|
||||||
j++
|
j++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -108,17 +109,17 @@ BuildRR:
|
|||||||
}
|
}
|
||||||
j += 2 + sep // Jump to it
|
j += 2 + sep // Jump to it
|
||||||
}
|
}
|
||||||
dom += fmt.Sprintf(mod, i+offset)
|
dom.WriteString(fmt.Sprintf(mod, i+offset))
|
||||||
default:
|
default:
|
||||||
if escape { // Pretty useless here
|
if escape { // Pretty useless here
|
||||||
escape = false
|
escape = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dom += string(s[j])
|
dom.WriteByte(s[j])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-parse the RR and send it on the current channel t
|
// Re-parse the RR and send it on the current channel t
|
||||||
rx, e := NewRR("$ORIGIN " + o + "\n" + dom)
|
rx, e := NewRR("$ORIGIN " + o + "\n" + dom.String())
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return e.(*ParseError).err
|
return e.(*ParseError).err
|
||||||
}
|
}
|
||||||
@@ -140,11 +141,11 @@ func modToPrintf(s string) (string, int, string) {
|
|||||||
return "", 0, "bad base in $GENERATE"
|
return "", 0, "bad base in $GENERATE"
|
||||||
}
|
}
|
||||||
offset, err := strconv.Atoi(xs[0])
|
offset, err := strconv.Atoi(xs[0])
|
||||||
if err != nil {
|
if err != nil || offset > 255 {
|
||||||
return "", 0, "bad offset in $GENERATE"
|
return "", 0, "bad offset in $GENERATE"
|
||||||
}
|
}
|
||||||
width, err := strconv.Atoi(xs[1])
|
width, err := strconv.Atoi(xs[1])
|
||||||
if err != nil {
|
if err != nil || width > 255 {
|
||||||
return "", offset, "bad width in $GENERATE"
|
return "", offset, "bad width in $GENERATE"
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
398
vendor/github.com/miekg/dns/zscan.go
generated
vendored
398
vendor/github.com/miekg/dns/zscan.go
generated
vendored
@@ -29,45 +29,45 @@ const maxUint16 = 1<<16 - 1
|
|||||||
// * Handle braces - anywhere.
|
// * Handle braces - anywhere.
|
||||||
const (
|
const (
|
||||||
// Zonefile
|
// Zonefile
|
||||||
_EOF = iota
|
zEOF = iota
|
||||||
_STRING
|
zString
|
||||||
_BLANK
|
zBlank
|
||||||
_QUOTE
|
zQuote
|
||||||
_NEWLINE
|
zNewline
|
||||||
_RRTYPE
|
zRrtpe
|
||||||
_OWNER
|
zOwner
|
||||||
_CLASS
|
zClass
|
||||||
_DIRORIGIN // $ORIGIN
|
zDirOrigin // $ORIGIN
|
||||||
_DIRTTL // $TTL
|
zDirTtl // $TTL
|
||||||
_DIRINCLUDE // $INCLUDE
|
zDirInclude // $INCLUDE
|
||||||
_DIRGENERATE // $GENERATE
|
zDirGenerate // $GENERATE
|
||||||
|
|
||||||
// Privatekey file
|
// Privatekey file
|
||||||
_VALUE
|
zValue
|
||||||
_KEY
|
zKey
|
||||||
|
|
||||||
_EXPECT_OWNER_DIR // Ownername
|
zExpectOwnerDir // Ownername
|
||||||
_EXPECT_OWNER_BL // Whitespace after the ownername
|
zExpectOwnerBl // Whitespace after the ownername
|
||||||
_EXPECT_ANY // Expect rrtype, ttl or class
|
zExpectAny // Expect rrtype, ttl or class
|
||||||
_EXPECT_ANY_NOCLASS // Expect rrtype or ttl
|
zExpectAnyNoClass // Expect rrtype or ttl
|
||||||
_EXPECT_ANY_NOCLASS_BL // The whitespace after _EXPECT_ANY_NOCLASS
|
zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
|
||||||
_EXPECT_ANY_NOTTL // Expect rrtype or class
|
zExpectAnyNoTtl // Expect rrtype or class
|
||||||
_EXPECT_ANY_NOTTL_BL // Whitespace after _EXPECT_ANY_NOTTL
|
zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
|
||||||
_EXPECT_RRTYPE // Expect rrtype
|
zExpectRrtype // Expect rrtype
|
||||||
_EXPECT_RRTYPE_BL // Whitespace BEFORE rrtype
|
zExpectRrtypeBl // Whitespace BEFORE rrtype
|
||||||
_EXPECT_RDATA // The first element of the rdata
|
zExpectRdata // The first element of the rdata
|
||||||
_EXPECT_DIRTTL_BL // Space after directive $TTL
|
zExpectDirTtlBl // Space after directive $TTL
|
||||||
_EXPECT_DIRTTL // Directive $TTL
|
zExpectDirTtl // Directive $TTL
|
||||||
_EXPECT_DIRORIGIN_BL // Space after directive $ORIGIN
|
zExpectDirOriginBl // Space after directive $ORIGIN
|
||||||
_EXPECT_DIRORIGIN // Directive $ORIGIN
|
zExpectDirOrigin // Directive $ORIGIN
|
||||||
_EXPECT_DIRINCLUDE_BL // Space after directive $INCLUDE
|
zExpectDirIncludeBl // Space after directive $INCLUDE
|
||||||
_EXPECT_DIRINCLUDE // Directive $INCLUDE
|
zExpectDirInclude // Directive $INCLUDE
|
||||||
_EXPECT_DIRGENERATE // Directive $GENERATE
|
zExpectDirGenerate // Directive $GENERATE
|
||||||
_EXPECT_DIRGENERATE_BL // Space after directive $GENERATE
|
zExpectDirGenerateBl // Space after directive $GENERATE
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
|
// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
|
||||||
// where the error occured.
|
// where the error occurred.
|
||||||
type ParseError struct {
|
type ParseError struct {
|
||||||
file string
|
file string
|
||||||
err string
|
err string
|
||||||
@@ -86,28 +86,32 @@ func (e *ParseError) Error() (s string) {
|
|||||||
type lex struct {
|
type lex struct {
|
||||||
token string // text of the token
|
token string // text of the token
|
||||||
tokenUpper string // uppercase text of the token
|
tokenUpper string // uppercase text of the token
|
||||||
length int // lenght of the token
|
length int // length of the token
|
||||||
err bool // when true, token text has lexer error
|
err bool // when true, token text has lexer error
|
||||||
value uint8 // value: _STRING, _BLANK, etc.
|
value uint8 // value: zString, _BLANK, etc.
|
||||||
line int // line in the file
|
line int // line in the file
|
||||||
column int // column in the file
|
column int // column in the file
|
||||||
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
|
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
|
||||||
comment string // any comment text seen
|
comment string // any comment text seen
|
||||||
}
|
}
|
||||||
|
|
||||||
// *Tokens are returned when a zone file is parsed.
|
// Token holds the token that are returned when a zone file is parsed.
|
||||||
type Token struct {
|
type Token struct {
|
||||||
RR // the scanned resource record when error is not nil
|
// The scanned resource record when error is not nil.
|
||||||
Error *ParseError // when an error occured, this has the error specifics
|
RR
|
||||||
Comment string // a potential comment positioned after the RR and on the same line
|
// When an error occurred, this has the error specifics.
|
||||||
|
Error *ParseError
|
||||||
|
// A potential comment positioned after the RR and on the same line.
|
||||||
|
Comment string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRR reads the RR contained in the string s. Only the first RR is returned.
|
// NewRR reads the RR contained in the string s. Only the first RR is
|
||||||
// The class defaults to IN and TTL defaults to 3600. The full zone file
|
// returned. If s contains no RR, return nil with no error. The class
|
||||||
// syntax like $TTL, $ORIGIN, etc. is supported.
|
// defaults to IN and TTL defaults to 3600. The full zone file syntax
|
||||||
// All fields of the returned RR are set, except RR.Header().Rdlength which is set to 0.
|
// like $TTL, $ORIGIN, etc. is supported. All fields of the returned
|
||||||
|
// RR are set, except RR.Header().Rdlength which is set to 0.
|
||||||
func NewRR(s string) (RR, error) {
|
func NewRR(s string) (RR, error) {
|
||||||
if s[len(s)-1] != '\n' { // We need a closing newline
|
if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
|
||||||
return ReadRR(strings.NewReader(s+"\n"), "")
|
return ReadRR(strings.NewReader(s+"\n"), "")
|
||||||
}
|
}
|
||||||
return ReadRR(strings.NewReader(s), "")
|
return ReadRR(strings.NewReader(s), "")
|
||||||
@@ -117,17 +121,21 @@ func NewRR(s string) (RR, error) {
|
|||||||
// See NewRR for more documentation.
|
// See NewRR for more documentation.
|
||||||
func ReadRR(q io.Reader, filename string) (RR, error) {
|
func ReadRR(q io.Reader, filename string) (RR, error) {
|
||||||
r := <-parseZoneHelper(q, ".", filename, 1)
|
r := <-parseZoneHelper(q, ".", filename, 1)
|
||||||
|
if r == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
if r.Error != nil {
|
if r.Error != nil {
|
||||||
return nil, r.Error
|
return nil, r.Error
|
||||||
}
|
}
|
||||||
return r.RR, nil
|
return r.RR, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseZone reads a RFC 1035 style one from r. It returns *Tokens on the
|
// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
|
||||||
// returned channel, which consist out the parsed RR, a potential comment or an error.
|
// returned channel, which consist out the parsed RR, a potential comment or an error.
|
||||||
// If there is an error the RR is nil. The string file is only used
|
// If there is an error the RR is nil. The string file is only used
|
||||||
// in error reporting. The string origin is used as the initial origin, as
|
// in error reporting. The string origin is used as the initial origin, as
|
||||||
// if the file would start with: $ORIGIN origin .
|
// if the file would start with: $ORIGIN origin .
|
||||||
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
|
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
|
||||||
// The channel t is closed by ParseZone when the end of r is reached.
|
// The channel t is closed by ParseZone when the end of r is reached.
|
||||||
//
|
//
|
||||||
@@ -136,15 +144,17 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
|
|||||||
//
|
//
|
||||||
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
|
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
|
||||||
// if x.Error != nil {
|
// if x.Error != nil {
|
||||||
// // Do something with x.RR
|
// // log.Println(x.Error)
|
||||||
// }
|
// } else {
|
||||||
|
// // Do something with x.RR
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Comments specified after an RR (and on the same line!) are returned too:
|
// Comments specified after an RR (and on the same line!) are returned too:
|
||||||
//
|
//
|
||||||
// foo. IN A 10.0.0.1 ; this is a comment
|
// foo. IN A 10.0.0.1 ; this is a comment
|
||||||
//
|
//
|
||||||
// The text "; this is comment" is returned in Token.Comment . Comments inside the
|
// The text "; this is comment" is returned in Token.Comment. Comments inside the
|
||||||
// RR are discarded. Comments on a line by themselves are discarded too.
|
// RR are discarded. Comments on a line by themselves are discarded too.
|
||||||
func ParseZone(r io.Reader, origin, file string) chan *Token {
|
func ParseZone(r io.Reader, origin, file string) chan *Token {
|
||||||
return parseZoneHelper(r, origin, file, 10000)
|
return parseZoneHelper(r, origin, file, 10000)
|
||||||
@@ -163,17 +173,17 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s := scanInit(r)
|
s := scanInit(r)
|
||||||
c := make(chan lex, 1000)
|
c := make(chan lex)
|
||||||
// Start the lexer
|
// Start the lexer
|
||||||
go zlexer(s, c)
|
go zlexer(s, c)
|
||||||
// 6 possible beginnings of a line, _ is a space
|
// 6 possible beginnings of a line, _ is a space
|
||||||
// 0. _RRTYPE -> all omitted until the rrtype
|
// 0. zRRTYPE -> all omitted until the rrtype
|
||||||
// 1. _OWNER _ _RRTYPE -> class/ttl omitted
|
// 1. zOwner _ zRrtype -> class/ttl omitted
|
||||||
// 2. _OWNER _ _STRING _ _RRTYPE -> class omitted
|
// 2. zOwner _ zString _ zRrtype -> class omitted
|
||||||
// 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class
|
// 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
|
||||||
// 4. _OWNER _ _CLASS _ _RRTYPE -> ttl omitted
|
// 4. zOwner _ zClass _ zRrtype -> ttl omitted
|
||||||
// 5. _OWNER _ _CLASS _ _STRING _ _RRTYPE -> class/ttl (reversed)
|
// 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
|
||||||
// After detecting these, we know the _RRTYPE so we can jump to functions
|
// After detecting these, we know the zRrtype so we can jump to functions
|
||||||
// handling the rdata for each of these types.
|
// handling the rdata for each of these types.
|
||||||
|
|
||||||
if origin == "" {
|
if origin == "" {
|
||||||
@@ -185,7 +195,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
st := _EXPECT_OWNER_DIR // initial state
|
st := zExpectOwnerDir // initial state
|
||||||
var h RR_Header
|
var h RR_Header
|
||||||
var defttl uint32 = defaultTtl
|
var defttl uint32 = defaultTtl
|
||||||
var prevName string
|
var prevName string
|
||||||
@@ -197,19 +207,19 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
switch st {
|
switch st {
|
||||||
case _EXPECT_OWNER_DIR:
|
case zExpectOwnerDir:
|
||||||
// We can also expect a directive, like $TTL or $ORIGIN
|
// We can also expect a directive, like $TTL or $ORIGIN
|
||||||
h.Ttl = defttl
|
h.Ttl = defttl
|
||||||
h.Class = ClassINET
|
h.Class = ClassINET
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _NEWLINE: // Empty line
|
case zNewline:
|
||||||
st = _EXPECT_OWNER_DIR
|
st = zExpectOwnerDir
|
||||||
case _OWNER:
|
case zOwner:
|
||||||
h.Name = l.token
|
h.Name = l.token
|
||||||
if l.token[0] == '@' {
|
if l.token[0] == '@' {
|
||||||
h.Name = origin
|
h.Name = origin
|
||||||
prevName = h.Name
|
prevName = h.Name
|
||||||
st = _EXPECT_OWNER_BL
|
st = zExpectOwnerBl
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if h.Name[l.length-1] != '.' {
|
if h.Name[l.length-1] != '.' {
|
||||||
@@ -221,59 +231,59 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
prevName = h.Name
|
prevName = h.Name
|
||||||
st = _EXPECT_OWNER_BL
|
st = zExpectOwnerBl
|
||||||
case _DIRTTL:
|
case zDirTtl:
|
||||||
st = _EXPECT_DIRTTL_BL
|
st = zExpectDirTtlBl
|
||||||
case _DIRORIGIN:
|
case zDirOrigin:
|
||||||
st = _EXPECT_DIRORIGIN_BL
|
st = zExpectDirOriginBl
|
||||||
case _DIRINCLUDE:
|
case zDirInclude:
|
||||||
st = _EXPECT_DIRINCLUDE_BL
|
st = zExpectDirIncludeBl
|
||||||
case _DIRGENERATE:
|
case zDirGenerate:
|
||||||
st = _EXPECT_DIRGENERATE_BL
|
st = zExpectDirGenerateBl
|
||||||
case _RRTYPE: // Everthing has been omitted, this is the first thing on the line
|
case zRrtpe:
|
||||||
h.Name = prevName
|
h.Name = prevName
|
||||||
h.Rrtype = l.torc
|
h.Rrtype = l.torc
|
||||||
st = _EXPECT_RDATA
|
st = zExpectRdata
|
||||||
case _CLASS: // First thing on the line is the class
|
case zClass:
|
||||||
h.Name = prevName
|
h.Name = prevName
|
||||||
h.Class = l.torc
|
h.Class = l.torc
|
||||||
st = _EXPECT_ANY_NOCLASS_BL
|
st = zExpectAnyNoClassBl
|
||||||
case _BLANK:
|
case zBlank:
|
||||||
// Discard, can happen when there is nothing on the
|
// Discard, can happen when there is nothing on the
|
||||||
// line except the RR type
|
// line except the RR type
|
||||||
case _STRING: // First thing on the is the ttl
|
case zString:
|
||||||
if ttl, ok := stringToTtl(l.token); !ok {
|
ttl, ok := stringToTtl(l.token)
|
||||||
|
if !ok {
|
||||||
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
h.Ttl = ttl
|
|
||||||
// Don't about the defttl, we should take the $TTL value
|
|
||||||
// defttl = ttl
|
|
||||||
}
|
}
|
||||||
st = _EXPECT_ANY_NOTTL_BL
|
h.Ttl = ttl
|
||||||
|
// Don't about the defttl, we should take the $TTL value
|
||||||
|
// defttl = ttl
|
||||||
|
st = zExpectAnyNoTtlBl
|
||||||
|
|
||||||
default:
|
default:
|
||||||
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
|
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case _EXPECT_DIRINCLUDE_BL:
|
case zExpectDirIncludeBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
|
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_DIRINCLUDE
|
st = zExpectDirInclude
|
||||||
case _EXPECT_DIRINCLUDE:
|
case zExpectDirInclude:
|
||||||
if l.value != _STRING {
|
if l.value != zString {
|
||||||
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
|
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
|
||||||
l := <-c
|
l := <-c
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _BLANK:
|
case zBlank:
|
||||||
l := <-c
|
l := <-c
|
||||||
if l.value == _STRING {
|
if l.value == zString {
|
||||||
if _, ok := IsDomainName(l.token); !ok {
|
if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
|
||||||
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
|
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -288,7 +298,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
neworigin = l.token
|
neworigin = l.token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case _NEWLINE, _EOF:
|
case zNewline, zEOF:
|
||||||
// Ok
|
// Ok
|
||||||
default:
|
default:
|
||||||
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
|
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
|
||||||
@@ -305,15 +315,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
parseZone(r1, l.token, neworigin, t, include+1)
|
parseZone(r1, l.token, neworigin, t, include+1)
|
||||||
st = _EXPECT_OWNER_DIR
|
st = zExpectOwnerDir
|
||||||
case _EXPECT_DIRTTL_BL:
|
case zExpectDirTtlBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
|
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_DIRTTL
|
st = zExpectDirTtl
|
||||||
case _EXPECT_DIRTTL:
|
case zExpectDirTtl:
|
||||||
if l.value != _STRING {
|
if l.value != zString {
|
||||||
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -321,21 +331,21 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
t <- &Token{Error: e}
|
t <- &Token{Error: e}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ttl, ok := stringToTtl(l.token); !ok {
|
ttl, ok := stringToTtl(l.token)
|
||||||
|
if !ok {
|
||||||
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
defttl = ttl
|
|
||||||
}
|
}
|
||||||
st = _EXPECT_OWNER_DIR
|
defttl = ttl
|
||||||
case _EXPECT_DIRORIGIN_BL:
|
st = zExpectOwnerDir
|
||||||
if l.value != _BLANK {
|
case zExpectDirOriginBl:
|
||||||
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
|
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_DIRORIGIN
|
st = zExpectDirOrigin
|
||||||
case _EXPECT_DIRORIGIN:
|
case zExpectDirOrigin:
|
||||||
if l.value != _STRING {
|
if l.value != zString {
|
||||||
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -355,15 +365,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
} else {
|
} else {
|
||||||
origin = l.token
|
origin = l.token
|
||||||
}
|
}
|
||||||
st = _EXPECT_OWNER_DIR
|
st = zExpectOwnerDir
|
||||||
case _EXPECT_DIRGENERATE_BL:
|
case zExpectDirGenerateBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
|
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_DIRGENERATE
|
st = zExpectDirGenerate
|
||||||
case _EXPECT_DIRGENERATE:
|
case zExpectDirGenerate:
|
||||||
if l.value != _STRING {
|
if l.value != zString {
|
||||||
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -371,90 +381,90 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
t <- &Token{Error: &ParseError{f, e, l}}
|
t <- &Token{Error: &ParseError{f, e, l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_OWNER_DIR
|
st = zExpectOwnerDir
|
||||||
case _EXPECT_OWNER_BL:
|
case zExpectOwnerBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
|
t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_ANY
|
st = zExpectAny
|
||||||
case _EXPECT_ANY:
|
case zExpectAny:
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _RRTYPE:
|
case zRrtpe:
|
||||||
h.Rrtype = l.torc
|
h.Rrtype = l.torc
|
||||||
st = _EXPECT_RDATA
|
st = zExpectRdata
|
||||||
case _CLASS:
|
case zClass:
|
||||||
h.Class = l.torc
|
h.Class = l.torc
|
||||||
st = _EXPECT_ANY_NOCLASS_BL
|
st = zExpectAnyNoClassBl
|
||||||
case _STRING: // TTL is this case
|
case zString:
|
||||||
if ttl, ok := stringToTtl(l.token); !ok {
|
ttl, ok := stringToTtl(l.token)
|
||||||
|
if !ok {
|
||||||
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
h.Ttl = ttl
|
|
||||||
// defttl = ttl // don't set the defttl here
|
|
||||||
}
|
}
|
||||||
st = _EXPECT_ANY_NOTTL_BL
|
h.Ttl = ttl
|
||||||
|
// defttl = ttl // don't set the defttl here
|
||||||
|
st = zExpectAnyNoTtlBl
|
||||||
default:
|
default:
|
||||||
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case _EXPECT_ANY_NOCLASS_BL:
|
case zExpectAnyNoClassBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank before class", l}}
|
t <- &Token{Error: &ParseError{f, "no blank before class", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_ANY_NOCLASS
|
st = zExpectAnyNoClass
|
||||||
case _EXPECT_ANY_NOTTL_BL:
|
case zExpectAnyNoTtlBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
|
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_ANY_NOTTL
|
st = zExpectAnyNoTtl
|
||||||
case _EXPECT_ANY_NOTTL:
|
case zExpectAnyNoTtl:
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _CLASS:
|
case zClass:
|
||||||
h.Class = l.torc
|
h.Class = l.torc
|
||||||
st = _EXPECT_RRTYPE_BL
|
st = zExpectRrtypeBl
|
||||||
case _RRTYPE:
|
case zRrtpe:
|
||||||
h.Rrtype = l.torc
|
h.Rrtype = l.torc
|
||||||
st = _EXPECT_RDATA
|
st = zExpectRdata
|
||||||
default:
|
default:
|
||||||
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case _EXPECT_ANY_NOCLASS:
|
case zExpectAnyNoClass:
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _STRING: // TTL
|
case zString:
|
||||||
if ttl, ok := stringToTtl(l.token); !ok {
|
ttl, ok := stringToTtl(l.token)
|
||||||
|
if !ok {
|
||||||
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
h.Ttl = ttl
|
|
||||||
// defttl = ttl // don't set the def ttl anymore
|
|
||||||
}
|
}
|
||||||
st = _EXPECT_RRTYPE_BL
|
h.Ttl = ttl
|
||||||
case _RRTYPE:
|
// defttl = ttl // don't set the def ttl anymore
|
||||||
|
st = zExpectRrtypeBl
|
||||||
|
case zRrtpe:
|
||||||
h.Rrtype = l.torc
|
h.Rrtype = l.torc
|
||||||
st = _EXPECT_RDATA
|
st = zExpectRdata
|
||||||
default:
|
default:
|
||||||
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
|
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case _EXPECT_RRTYPE_BL:
|
case zExpectRrtypeBl:
|
||||||
if l.value != _BLANK {
|
if l.value != zBlank {
|
||||||
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
|
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
st = _EXPECT_RRTYPE
|
st = zExpectRrtype
|
||||||
case _EXPECT_RRTYPE:
|
case zExpectRrtype:
|
||||||
if l.value != _RRTYPE {
|
if l.value != zRrtpe {
|
||||||
t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
|
t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.Rrtype = l.torc
|
h.Rrtype = l.torc
|
||||||
st = _EXPECT_RDATA
|
st = zExpectRdata
|
||||||
case _EXPECT_RDATA:
|
case zExpectRdata:
|
||||||
r, e, c1 := setRR(h, c, origin, f)
|
r, e, c1 := setRR(h, c, origin, f)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
// If e.lex is nil than we have encounter a unknown RR type
|
// If e.lex is nil than we have encounter a unknown RR type
|
||||||
@@ -466,7 +476,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
t <- &Token{RR: r, Comment: c1}
|
t <- &Token{RR: r, Comment: c1}
|
||||||
st = _EXPECT_OWNER_DIR
|
st = zExpectOwnerDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
|
// If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
|
||||||
@@ -492,14 +502,14 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
for err == nil {
|
for err == nil {
|
||||||
l.column = s.position.Column
|
l.column = s.position.Column
|
||||||
l.line = s.position.Line
|
l.line = s.position.Line
|
||||||
if stri > maxTok {
|
if stri >= maxTok {
|
||||||
l.token = "token length insufficient for parsing"
|
l.token = "token length insufficient for parsing"
|
||||||
l.err = true
|
l.err = true
|
||||||
debug.Printf("[%+v]", l.token)
|
debug.Printf("[%+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if comi > maxTok {
|
if comi >= maxTok {
|
||||||
l.token = "comment length insufficient for parsing"
|
l.token = "comment length insufficient for parsing"
|
||||||
l.err = true
|
l.err = true
|
||||||
debug.Printf("[%+v]", l.token)
|
debug.Printf("[%+v]", l.token)
|
||||||
@@ -530,60 +540,60 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
// Space directly in the beginning, handled in the grammar
|
// Space directly in the beginning, handled in the grammar
|
||||||
} else if owner {
|
} else if owner {
|
||||||
// If we have a string and its the first, make it an owner
|
// If we have a string and its the first, make it an owner
|
||||||
l.value = _OWNER
|
l.value = zOwner
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
l.tokenUpper = strings.ToUpper(l.token)
|
l.tokenUpper = strings.ToUpper(l.token)
|
||||||
l.length = stri
|
l.length = stri
|
||||||
// escape $... start with a \ not a $, so this will work
|
// escape $... start with a \ not a $, so this will work
|
||||||
switch l.tokenUpper {
|
switch l.tokenUpper {
|
||||||
case "$TTL":
|
case "$TTL":
|
||||||
l.value = _DIRTTL
|
l.value = zDirTtl
|
||||||
case "$ORIGIN":
|
case "$ORIGIN":
|
||||||
l.value = _DIRORIGIN
|
l.value = zDirOrigin
|
||||||
case "$INCLUDE":
|
case "$INCLUDE":
|
||||||
l.value = _DIRINCLUDE
|
l.value = zDirInclude
|
||||||
case "$GENERATE":
|
case "$GENERATE":
|
||||||
l.value = _DIRGENERATE
|
l.value = zDirGenerate
|
||||||
}
|
}
|
||||||
debug.Printf("[7 %+v]", l.token)
|
debug.Printf("[7 %+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
} else {
|
} else {
|
||||||
l.value = _STRING
|
l.value = zString
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
l.tokenUpper = strings.ToUpper(l.token)
|
l.tokenUpper = strings.ToUpper(l.token)
|
||||||
l.length = stri
|
l.length = stri
|
||||||
if !rrtype {
|
if !rrtype {
|
||||||
if t, ok := StringToType[l.tokenUpper]; ok {
|
if t, ok := StringToType[l.tokenUpper]; ok {
|
||||||
l.value = _RRTYPE
|
l.value = zRrtpe
|
||||||
l.torc = t
|
l.torc = t
|
||||||
rrtype = true
|
rrtype = true
|
||||||
} else {
|
} else {
|
||||||
if strings.HasPrefix(l.tokenUpper, "TYPE") {
|
if strings.HasPrefix(l.tokenUpper, "TYPE") {
|
||||||
if t, ok := typeToInt(l.token); !ok {
|
t, ok := typeToInt(l.token)
|
||||||
|
if !ok {
|
||||||
l.token = "unknown RR type"
|
l.token = "unknown RR type"
|
||||||
l.err = true
|
l.err = true
|
||||||
c <- l
|
c <- l
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
l.value = _RRTYPE
|
|
||||||
l.torc = t
|
|
||||||
}
|
}
|
||||||
|
l.value = zRrtpe
|
||||||
|
l.torc = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t, ok := StringToClass[l.tokenUpper]; ok {
|
if t, ok := StringToClass[l.tokenUpper]; ok {
|
||||||
l.value = _CLASS
|
l.value = zClass
|
||||||
l.torc = t
|
l.torc = t
|
||||||
} else {
|
} else {
|
||||||
if strings.HasPrefix(l.tokenUpper, "CLASS") {
|
if strings.HasPrefix(l.tokenUpper, "CLASS") {
|
||||||
if t, ok := classToInt(l.token); !ok {
|
t, ok := classToInt(l.token)
|
||||||
|
if !ok {
|
||||||
l.token = "unknown class"
|
l.token = "unknown class"
|
||||||
l.err = true
|
l.err = true
|
||||||
c <- l
|
c <- l
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
l.value = _CLASS
|
|
||||||
l.torc = t
|
|
||||||
}
|
}
|
||||||
|
l.value = zClass
|
||||||
|
l.torc = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,7 +603,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
stri = 0
|
stri = 0
|
||||||
// I reverse space stuff here
|
// I reverse space stuff here
|
||||||
if !space && !commt {
|
if !space && !commt {
|
||||||
l.value = _BLANK
|
l.value = zBlank
|
||||||
l.token = " "
|
l.token = " "
|
||||||
l.length = 1
|
l.length = 1
|
||||||
debug.Printf("[5 %+v]", l.token)
|
debug.Printf("[5 %+v]", l.token)
|
||||||
@@ -615,7 +625,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if stri > 0 {
|
if stri > 0 {
|
||||||
l.value = _STRING
|
l.value = zString
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
l.length = stri
|
l.length = stri
|
||||||
debug.Printf("[4 %+v]", l.token)
|
debug.Printf("[4 %+v]", l.token)
|
||||||
@@ -651,7 +661,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
if brace == 0 {
|
if brace == 0 {
|
||||||
owner = true
|
owner = true
|
||||||
owner = true
|
owner = true
|
||||||
l.value = _NEWLINE
|
l.value = zNewline
|
||||||
l.token = "\n"
|
l.token = "\n"
|
||||||
l.length = 1
|
l.length = 1
|
||||||
l.comment = string(com[:comi])
|
l.comment = string(com[:comi])
|
||||||
@@ -669,14 +679,14 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
if brace == 0 {
|
if brace == 0 {
|
||||||
// If there is previous text, we should output it here
|
// If there is previous text, we should output it here
|
||||||
if stri != 0 {
|
if stri != 0 {
|
||||||
l.value = _STRING
|
l.value = zString
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
l.tokenUpper = strings.ToUpper(l.token)
|
l.tokenUpper = strings.ToUpper(l.token)
|
||||||
|
|
||||||
l.length = stri
|
l.length = stri
|
||||||
if !rrtype {
|
if !rrtype {
|
||||||
if t, ok := StringToType[l.tokenUpper]; ok {
|
if t, ok := StringToType[l.tokenUpper]; ok {
|
||||||
l.value = _RRTYPE
|
l.value = zRrtpe
|
||||||
l.torc = t
|
l.torc = t
|
||||||
rrtype = true
|
rrtype = true
|
||||||
}
|
}
|
||||||
@@ -684,7 +694,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
debug.Printf("[2 %+v]", l.token)
|
debug.Printf("[2 %+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
}
|
}
|
||||||
l.value = _NEWLINE
|
l.value = zNewline
|
||||||
l.token = "\n"
|
l.token = "\n"
|
||||||
l.length = 1
|
l.length = 1
|
||||||
debug.Printf("[1 %+v]", l.token)
|
debug.Printf("[1 %+v]", l.token)
|
||||||
@@ -728,7 +738,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
space = false
|
space = false
|
||||||
// send previous gathered text and the quote
|
// send previous gathered text and the quote
|
||||||
if stri != 0 {
|
if stri != 0 {
|
||||||
l.value = _STRING
|
l.value = zString
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
l.length = stri
|
l.length = stri
|
||||||
|
|
||||||
@@ -738,7 +748,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send quote itself as separate token
|
// send quote itself as separate token
|
||||||
l.value = _QUOTE
|
l.value = zQuote
|
||||||
l.token = "\""
|
l.token = "\""
|
||||||
l.length = 1
|
l.length = 1
|
||||||
c <- l
|
c <- l
|
||||||
@@ -790,7 +800,7 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
// Send remainder
|
// Send remainder
|
||||||
l.token = string(str[:stri])
|
l.token = string(str[:stri])
|
||||||
l.length = stri
|
l.length = stri
|
||||||
l.value = _STRING
|
l.value = zString
|
||||||
debug.Printf("[%+v]", l.token)
|
debug.Printf("[%+v]", l.token)
|
||||||
c <- l
|
c <- l
|
||||||
}
|
}
|
||||||
@@ -798,7 +808,11 @@ func zlexer(s *scan, c chan lex) {
|
|||||||
|
|
||||||
// Extract the class number from CLASSxx
|
// Extract the class number from CLASSxx
|
||||||
func classToInt(token string) (uint16, bool) {
|
func classToInt(token string) (uint16, bool) {
|
||||||
class, ok := strconv.Atoi(token[5:])
|
offset := 5
|
||||||
|
if len(token) < offset+1 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
class, ok := strconv.Atoi(token[offset:])
|
||||||
if ok != nil || class > maxUint16 {
|
if ok != nil || class > maxUint16 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -807,7 +821,11 @@ func classToInt(token string) (uint16, bool) {
|
|||||||
|
|
||||||
// Extract the rr number from TYPExxx
|
// Extract the rr number from TYPExxx
|
||||||
func typeToInt(token string) (uint16, bool) {
|
func typeToInt(token string) (uint16, bool) {
|
||||||
typ, ok := strconv.Atoi(token[4:])
|
offset := 4
|
||||||
|
if len(token) < offset+1 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
typ, ok := strconv.Atoi(token[offset:])
|
||||||
if ok != nil || typ > maxUint16 {
|
if ok != nil || typ > maxUint16 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -922,15 +940,15 @@ func slurpRemainder(c chan lex, f string) (*ParseError, string) {
|
|||||||
l := <-c
|
l := <-c
|
||||||
com := ""
|
com := ""
|
||||||
switch l.value {
|
switch l.value {
|
||||||
case _BLANK:
|
case zBlank:
|
||||||
l = <-c
|
l = <-c
|
||||||
com = l.comment
|
com = l.comment
|
||||||
if l.value != _NEWLINE && l.value != _EOF {
|
if l.value != zNewline && l.value != zEOF {
|
||||||
return &ParseError{f, "garbage after rdata", l}, ""
|
return &ParseError{f, "garbage after rdata", l}, ""
|
||||||
}
|
}
|
||||||
case _NEWLINE:
|
case zNewline:
|
||||||
com = l.comment
|
com = l.comment
|
||||||
case _EOF:
|
case zEOF:
|
||||||
default:
|
default:
|
||||||
return &ParseError{f, "garbage after rdata", l}, ""
|
return &ParseError{f, "garbage after rdata", l}, ""
|
||||||
}
|
}
|
||||||
|
|||||||
1155
vendor/github.com/miekg/dns/zscan_rr.go
generated
vendored
1155
vendor/github.com/miekg/dns/zscan_rr.go
generated
vendored
File diff suppressed because it is too large
Load Diff
842
vendor/github.com/miekg/dns/ztypes.go
generated
vendored
Normal file
842
vendor/github.com/miekg/dns/ztypes.go
generated
vendored
Normal file
@@ -0,0 +1,842 @@
|
|||||||
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TypeToRR is a map of constructors for each RR type.
|
||||||
|
var TypeToRR = map[uint16]func() RR{
|
||||||
|
TypeA: func() RR { return new(A) },
|
||||||
|
TypeAAAA: func() RR { return new(AAAA) },
|
||||||
|
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||||
|
TypeANY: func() RR { return new(ANY) },
|
||||||
|
TypeCAA: func() RR { return new(CAA) },
|
||||||
|
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
|
||||||
|
TypeCDS: func() RR { return new(CDS) },
|
||||||
|
TypeCERT: func() RR { return new(CERT) },
|
||||||
|
TypeCNAME: func() RR { return new(CNAME) },
|
||||||
|
TypeDHCID: func() RR { return new(DHCID) },
|
||||||
|
TypeDLV: func() RR { return new(DLV) },
|
||||||
|
TypeDNAME: func() RR { return new(DNAME) },
|
||||||
|
TypeDNSKEY: func() RR { return new(DNSKEY) },
|
||||||
|
TypeDS: func() RR { return new(DS) },
|
||||||
|
TypeEID: func() RR { return new(EID) },
|
||||||
|
TypeEUI48: func() RR { return new(EUI48) },
|
||||||
|
TypeEUI64: func() RR { return new(EUI64) },
|
||||||
|
TypeGID: func() RR { return new(GID) },
|
||||||
|
TypeGPOS: func() RR { return new(GPOS) },
|
||||||
|
TypeHINFO: func() RR { return new(HINFO) },
|
||||||
|
TypeHIP: func() RR { return new(HIP) },
|
||||||
|
TypeIPSECKEY: func() RR { return new(IPSECKEY) },
|
||||||
|
TypeKEY: func() RR { return new(KEY) },
|
||||||
|
TypeKX: func() RR { return new(KX) },
|
||||||
|
TypeL32: func() RR { return new(L32) },
|
||||||
|
TypeL64: func() RR { return new(L64) },
|
||||||
|
TypeLOC: func() RR { return new(LOC) },
|
||||||
|
TypeLP: func() RR { return new(LP) },
|
||||||
|
TypeMB: func() RR { return new(MB) },
|
||||||
|
TypeMD: func() RR { return new(MD) },
|
||||||
|
TypeMF: func() RR { return new(MF) },
|
||||||
|
TypeMG: func() RR { return new(MG) },
|
||||||
|
TypeMINFO: func() RR { return new(MINFO) },
|
||||||
|
TypeMR: func() RR { return new(MR) },
|
||||||
|
TypeMX: func() RR { return new(MX) },
|
||||||
|
TypeNAPTR: func() RR { return new(NAPTR) },
|
||||||
|
TypeNID: func() RR { return new(NID) },
|
||||||
|
TypeNIMLOC: func() RR { return new(NIMLOC) },
|
||||||
|
TypeNINFO: func() RR { return new(NINFO) },
|
||||||
|
TypeNS: func() RR { return new(NS) },
|
||||||
|
TypeNSAPPTR: func() RR { return new(NSAPPTR) },
|
||||||
|
TypeNSEC: func() RR { return new(NSEC) },
|
||||||
|
TypeNSEC3: func() RR { return new(NSEC3) },
|
||||||
|
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
|
||||||
|
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
|
||||||
|
TypeOPT: func() RR { return new(OPT) },
|
||||||
|
TypePTR: func() RR { return new(PTR) },
|
||||||
|
TypePX: func() RR { return new(PX) },
|
||||||
|
TypeRKEY: func() RR { return new(RKEY) },
|
||||||
|
TypeRP: func() RR { return new(RP) },
|
||||||
|
TypeRRSIG: func() RR { return new(RRSIG) },
|
||||||
|
TypeRT: func() RR { return new(RT) },
|
||||||
|
TypeSIG: func() RR { return new(SIG) },
|
||||||
|
TypeSOA: func() RR { return new(SOA) },
|
||||||
|
TypeSPF: func() RR { return new(SPF) },
|
||||||
|
TypeSRV: func() RR { return new(SRV) },
|
||||||
|
TypeSSHFP: func() RR { return new(SSHFP) },
|
||||||
|
TypeTA: func() RR { return new(TA) },
|
||||||
|
TypeTALINK: func() RR { return new(TALINK) },
|
||||||
|
TypeTKEY: func() RR { return new(TKEY) },
|
||||||
|
TypeTLSA: func() RR { return new(TLSA) },
|
||||||
|
TypeTSIG: func() RR { return new(TSIG) },
|
||||||
|
TypeTXT: func() RR { return new(TXT) },
|
||||||
|
TypeUID: func() RR { return new(UID) },
|
||||||
|
TypeUINFO: func() RR { return new(UINFO) },
|
||||||
|
TypeURI: func() RR { return new(URI) },
|
||||||
|
TypeWKS: func() RR { return new(WKS) },
|
||||||
|
TypeX25: func() RR { return new(X25) },
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeToString is a map of strings for each RR type.
|
||||||
|
var TypeToString = map[uint16]string{
|
||||||
|
TypeA: "A",
|
||||||
|
TypeAAAA: "AAAA",
|
||||||
|
TypeAFSDB: "AFSDB",
|
||||||
|
TypeANY: "ANY",
|
||||||
|
TypeATMA: "ATMA",
|
||||||
|
TypeAXFR: "AXFR",
|
||||||
|
TypeCAA: "CAA",
|
||||||
|
TypeCDNSKEY: "CDNSKEY",
|
||||||
|
TypeCDS: "CDS",
|
||||||
|
TypeCERT: "CERT",
|
||||||
|
TypeCNAME: "CNAME",
|
||||||
|
TypeDHCID: "DHCID",
|
||||||
|
TypeDLV: "DLV",
|
||||||
|
TypeDNAME: "DNAME",
|
||||||
|
TypeDNSKEY: "DNSKEY",
|
||||||
|
TypeDS: "DS",
|
||||||
|
TypeEID: "EID",
|
||||||
|
TypeEUI48: "EUI48",
|
||||||
|
TypeEUI64: "EUI64",
|
||||||
|
TypeGID: "GID",
|
||||||
|
TypeGPOS: "GPOS",
|
||||||
|
TypeHINFO: "HINFO",
|
||||||
|
TypeHIP: "HIP",
|
||||||
|
TypeIPSECKEY: "IPSECKEY",
|
||||||
|
TypeISDN: "ISDN",
|
||||||
|
TypeIXFR: "IXFR",
|
||||||
|
TypeKEY: "KEY",
|
||||||
|
TypeKX: "KX",
|
||||||
|
TypeL32: "L32",
|
||||||
|
TypeL64: "L64",
|
||||||
|
TypeLOC: "LOC",
|
||||||
|
TypeLP: "LP",
|
||||||
|
TypeMAILA: "MAILA",
|
||||||
|
TypeMAILB: "MAILB",
|
||||||
|
TypeMB: "MB",
|
||||||
|
TypeMD: "MD",
|
||||||
|
TypeMF: "MF",
|
||||||
|
TypeMG: "MG",
|
||||||
|
TypeMINFO: "MINFO",
|
||||||
|
TypeMR: "MR",
|
||||||
|
TypeMX: "MX",
|
||||||
|
TypeNAPTR: "NAPTR",
|
||||||
|
TypeNID: "NID",
|
||||||
|
TypeNIMLOC: "NIMLOC",
|
||||||
|
TypeNINFO: "NINFO",
|
||||||
|
TypeNS: "NS",
|
||||||
|
TypeNSEC: "NSEC",
|
||||||
|
TypeNSEC3: "NSEC3",
|
||||||
|
TypeNSEC3PARAM: "NSEC3PARAM",
|
||||||
|
TypeNULL: "NULL",
|
||||||
|
TypeNXT: "NXT",
|
||||||
|
TypeNone: "None",
|
||||||
|
TypeOPENPGPKEY: "OPENPGPKEY",
|
||||||
|
TypeOPT: "OPT",
|
||||||
|
TypePTR: "PTR",
|
||||||
|
TypePX: "PX",
|
||||||
|
TypeRKEY: "RKEY",
|
||||||
|
TypeRP: "RP",
|
||||||
|
TypeRRSIG: "RRSIG",
|
||||||
|
TypeRT: "RT",
|
||||||
|
TypeReserved: "Reserved",
|
||||||
|
TypeSIG: "SIG",
|
||||||
|
TypeSOA: "SOA",
|
||||||
|
TypeSPF: "SPF",
|
||||||
|
TypeSRV: "SRV",
|
||||||
|
TypeSSHFP: "SSHFP",
|
||||||
|
TypeTA: "TA",
|
||||||
|
TypeTALINK: "TALINK",
|
||||||
|
TypeTKEY: "TKEY",
|
||||||
|
TypeTLSA: "TLSA",
|
||||||
|
TypeTSIG: "TSIG",
|
||||||
|
TypeTXT: "TXT",
|
||||||
|
TypeUID: "UID",
|
||||||
|
TypeUINFO: "UINFO",
|
||||||
|
TypeUNSPEC: "UNSPEC",
|
||||||
|
TypeURI: "URI",
|
||||||
|
TypeWKS: "WKS",
|
||||||
|
TypeX25: "X25",
|
||||||
|
TypeNSAPPTR: "NSAP-PTR",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header() functions
|
||||||
|
func (rr *A) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *DS) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *EID) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *GID) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *KX) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *L64) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *LP) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MD) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MF) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MR) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *MX) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NID) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NS) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *RP) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *TA) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *TSIG) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *UID) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *URI) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
func (rr *X25) Header() *RR_Header { return &rr.Hdr }
|
||||||
|
|
||||||
|
// len() functions
|
||||||
|
func (rr *A) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += net.IPv4len // A
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *AAAA) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += net.IPv6len // AAAA
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *AFSDB) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Subtype
|
||||||
|
l += len(rr.Hostname) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *ANY) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *CAA) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 1 // Flag
|
||||||
|
l += len(rr.Tag) + 1
|
||||||
|
l += len(rr.Value)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *CERT) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Type
|
||||||
|
l += 2 // KeyTag
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *CNAME) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Target) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *DHCID) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.Digest))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *DNAME) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Target) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *DNSKEY) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Flags
|
||||||
|
l += 1 // Protocol
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *DS) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // KeyTag
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += 1 // DigestType
|
||||||
|
l += len(rr.Digest)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *EID) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Endpoint)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *EUI48) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 6 // Address
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *EUI64) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 8 // Address
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *GID) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 4 // Gid
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *GPOS) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Longitude) + 1
|
||||||
|
l += len(rr.Latitude) + 1
|
||||||
|
l += len(rr.Altitude) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *HINFO) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Cpu) + 1
|
||||||
|
l += len(rr.Os) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *HIP) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 1 // HitLength
|
||||||
|
l += 1 // PublicKeyAlgorithm
|
||||||
|
l += 2 // PublicKeyLength
|
||||||
|
l += len(rr.Hit)/2 + 1
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
|
for _, x := range rr.RendezvousServers {
|
||||||
|
l += len(x) + 1
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *KX) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += len(rr.Exchanger) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *L32) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += net.IPv4len // Locator32
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *L64) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += 8 // Locator64
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *LOC) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 1 // Version
|
||||||
|
l += 1 // Size
|
||||||
|
l += 1 // HorizPre
|
||||||
|
l += 1 // VertPre
|
||||||
|
l += 4 // Latitude
|
||||||
|
l += 4 // Longitude
|
||||||
|
l += 4 // Altitude
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *LP) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += len(rr.Fqdn) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MB) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Mb) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MD) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Md) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MF) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Mf) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MG) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Mg) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MINFO) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Rmail) + 1
|
||||||
|
l += len(rr.Email) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MR) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Mr) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *MX) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += len(rr.Mx) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NAPTR) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Order
|
||||||
|
l += 2 // Preference
|
||||||
|
l += len(rr.Flags) + 1
|
||||||
|
l += len(rr.Service) + 1
|
||||||
|
l += len(rr.Regexp) + 1
|
||||||
|
l += len(rr.Replacement) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NID) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += 8 // NodeID
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NIMLOC) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Locator)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NINFO) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
for _, x := range rr.ZSData {
|
||||||
|
l += len(x) + 1
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NS) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Ns) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NSAPPTR) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Ptr) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *NSEC3PARAM) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 1 // Hash
|
||||||
|
l += 1 // Flags
|
||||||
|
l += 2 // Iterations
|
||||||
|
l += 1 // SaltLength
|
||||||
|
l += len(rr.Salt)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *OPENPGPKEY) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *PTR) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Ptr) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *PX) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += len(rr.Map822) + 1
|
||||||
|
l += len(rr.Mapx400) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *RFC3597) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Rdata)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *RKEY) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Flags
|
||||||
|
l += 1 // Protocol
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *RP) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Mbox) + 1
|
||||||
|
l += len(rr.Txt) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *RRSIG) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // TypeCovered
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += 1 // Labels
|
||||||
|
l += 4 // OrigTtl
|
||||||
|
l += 4 // Expiration
|
||||||
|
l += 4 // Inception
|
||||||
|
l += 2 // KeyTag
|
||||||
|
l += len(rr.SignerName) + 1
|
||||||
|
l += base64.StdEncoding.DecodedLen(len(rr.Signature))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *RT) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Preference
|
||||||
|
l += len(rr.Host) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *SOA) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Ns) + 1
|
||||||
|
l += len(rr.Mbox) + 1
|
||||||
|
l += 4 // Serial
|
||||||
|
l += 4 // Refresh
|
||||||
|
l += 4 // Retry
|
||||||
|
l += 4 // Expire
|
||||||
|
l += 4 // Minttl
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *SPF) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
for _, x := range rr.Txt {
|
||||||
|
l += len(x) + 1
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *SRV) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Priority
|
||||||
|
l += 2 // Weight
|
||||||
|
l += 2 // Port
|
||||||
|
l += len(rr.Target) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *SSHFP) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += 1 // Type
|
||||||
|
l += len(rr.FingerPrint)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *TA) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // KeyTag
|
||||||
|
l += 1 // Algorithm
|
||||||
|
l += 1 // DigestType
|
||||||
|
l += len(rr.Digest)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *TALINK) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.PreviousName) + 1
|
||||||
|
l += len(rr.NextName) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *TKEY) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Algorithm) + 1
|
||||||
|
l += 4 // Inception
|
||||||
|
l += 4 // Expiration
|
||||||
|
l += 2 // Mode
|
||||||
|
l += 2 // Error
|
||||||
|
l += 2 // KeySize
|
||||||
|
l += len(rr.Key) + 1
|
||||||
|
l += 2 // OtherLen
|
||||||
|
l += len(rr.OtherData) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *TLSA) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 1 // Usage
|
||||||
|
l += 1 // Selector
|
||||||
|
l += 1 // MatchingType
|
||||||
|
l += len(rr.Certificate)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *TSIG) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Algorithm) + 1
|
||||||
|
l += 6 // TimeSigned
|
||||||
|
l += 2 // Fudge
|
||||||
|
l += 2 // MACSize
|
||||||
|
l += len(rr.MAC)/2 + 1
|
||||||
|
l += 2 // OrigId
|
||||||
|
l += 2 // Error
|
||||||
|
l += 2 // OtherLen
|
||||||
|
l += len(rr.OtherData)/2 + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *TXT) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
for _, x := range rr.Txt {
|
||||||
|
l += len(x) + 1
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *UID) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 4 // Uid
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *UINFO) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.Uinfo) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *URI) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += 2 // Priority
|
||||||
|
l += 2 // Weight
|
||||||
|
l += len(rr.Target)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
func (rr *X25) len() int {
|
||||||
|
l := rr.Hdr.len()
|
||||||
|
l += len(rr.PSDNAddress) + 1
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy() functions
|
||||||
|
func (rr *A) copy() RR {
|
||||||
|
return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)}
|
||||||
|
}
|
||||||
|
func (rr *AAAA) copy() RR {
|
||||||
|
return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)}
|
||||||
|
}
|
||||||
|
func (rr *AFSDB) copy() RR {
|
||||||
|
return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname}
|
||||||
|
}
|
||||||
|
func (rr *ANY) copy() RR {
|
||||||
|
return &ANY{*rr.Hdr.copyHeader()}
|
||||||
|
}
|
||||||
|
func (rr *CAA) copy() RR {
|
||||||
|
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
|
||||||
|
}
|
||||||
|
func (rr *CERT) copy() RR {
|
||||||
|
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
|
||||||
|
}
|
||||||
|
func (rr *CNAME) copy() RR {
|
||||||
|
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||||
|
}
|
||||||
|
func (rr *DHCID) copy() RR {
|
||||||
|
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
||||||
|
}
|
||||||
|
func (rr *DNAME) copy() RR {
|
||||||
|
return &DNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||||
|
}
|
||||||
|
func (rr *DNSKEY) copy() RR {
|
||||||
|
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||||
|
}
|
||||||
|
func (rr *DS) copy() RR {
|
||||||
|
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||||
|
}
|
||||||
|
func (rr *EID) copy() RR {
|
||||||
|
return &EID{*rr.Hdr.copyHeader(), rr.Endpoint}
|
||||||
|
}
|
||||||
|
func (rr *EUI48) copy() RR {
|
||||||
|
return &EUI48{*rr.Hdr.copyHeader(), rr.Address}
|
||||||
|
}
|
||||||
|
func (rr *EUI64) copy() RR {
|
||||||
|
return &EUI64{*rr.Hdr.copyHeader(), rr.Address}
|
||||||
|
}
|
||||||
|
func (rr *GID) copy() RR {
|
||||||
|
return &GID{*rr.Hdr.copyHeader(), rr.Gid}
|
||||||
|
}
|
||||||
|
func (rr *GPOS) copy() RR {
|
||||||
|
return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude}
|
||||||
|
}
|
||||||
|
func (rr *HINFO) copy() RR {
|
||||||
|
return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os}
|
||||||
|
}
|
||||||
|
func (rr *HIP) copy() RR {
|
||||||
|
RendezvousServers := make([]string, len(rr.RendezvousServers))
|
||||||
|
copy(RendezvousServers, rr.RendezvousServers)
|
||||||
|
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
|
||||||
|
}
|
||||||
|
func (rr *IPSECKEY) copy() RR {
|
||||||
|
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, copyIP(rr.GatewayA), copyIP(rr.GatewayAAAA), rr.GatewayName, rr.PublicKey}
|
||||||
|
}
|
||||||
|
func (rr *KX) copy() RR {
|
||||||
|
return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger}
|
||||||
|
}
|
||||||
|
func (rr *L32) copy() RR {
|
||||||
|
return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)}
|
||||||
|
}
|
||||||
|
func (rr *L64) copy() RR {
|
||||||
|
return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64}
|
||||||
|
}
|
||||||
|
func (rr *LOC) copy() RR {
|
||||||
|
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
|
||||||
|
}
|
||||||
|
func (rr *LP) copy() RR {
|
||||||
|
return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn}
|
||||||
|
}
|
||||||
|
func (rr *MB) copy() RR {
|
||||||
|
return &MB{*rr.Hdr.copyHeader(), rr.Mb}
|
||||||
|
}
|
||||||
|
func (rr *MD) copy() RR {
|
||||||
|
return &MD{*rr.Hdr.copyHeader(), rr.Md}
|
||||||
|
}
|
||||||
|
func (rr *MF) copy() RR {
|
||||||
|
return &MF{*rr.Hdr.copyHeader(), rr.Mf}
|
||||||
|
}
|
||||||
|
func (rr *MG) copy() RR {
|
||||||
|
return &MG{*rr.Hdr.copyHeader(), rr.Mg}
|
||||||
|
}
|
||||||
|
func (rr *MINFO) copy() RR {
|
||||||
|
return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email}
|
||||||
|
}
|
||||||
|
func (rr *MR) copy() RR {
|
||||||
|
return &MR{*rr.Hdr.copyHeader(), rr.Mr}
|
||||||
|
}
|
||||||
|
func (rr *MX) copy() RR {
|
||||||
|
return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx}
|
||||||
|
}
|
||||||
|
func (rr *NAPTR) copy() RR {
|
||||||
|
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
|
||||||
|
}
|
||||||
|
func (rr *NID) copy() RR {
|
||||||
|
return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID}
|
||||||
|
}
|
||||||
|
func (rr *NIMLOC) copy() RR {
|
||||||
|
return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator}
|
||||||
|
}
|
||||||
|
func (rr *NINFO) copy() RR {
|
||||||
|
ZSData := make([]string, len(rr.ZSData))
|
||||||
|
copy(ZSData, rr.ZSData)
|
||||||
|
return &NINFO{*rr.Hdr.copyHeader(), ZSData}
|
||||||
|
}
|
||||||
|
func (rr *NS) copy() RR {
|
||||||
|
return &NS{*rr.Hdr.copyHeader(), rr.Ns}
|
||||||
|
}
|
||||||
|
func (rr *NSAPPTR) copy() RR {
|
||||||
|
return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||||
|
}
|
||||||
|
func (rr *NSEC) copy() RR {
|
||||||
|
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||||
|
copy(TypeBitMap, rr.TypeBitMap)
|
||||||
|
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap}
|
||||||
|
}
|
||||||
|
func (rr *NSEC3) copy() RR {
|
||||||
|
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||||
|
copy(TypeBitMap, rr.TypeBitMap)
|
||||||
|
return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
|
||||||
|
}
|
||||||
|
func (rr *NSEC3PARAM) copy() RR {
|
||||||
|
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
||||||
|
}
|
||||||
|
func (rr *OPENPGPKEY) copy() RR {
|
||||||
|
return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey}
|
||||||
|
}
|
||||||
|
func (rr *OPT) copy() RR {
|
||||||
|
Option := make([]EDNS0, len(rr.Option))
|
||||||
|
copy(Option, rr.Option)
|
||||||
|
return &OPT{*rr.Hdr.copyHeader(), Option}
|
||||||
|
}
|
||||||
|
func (rr *PTR) copy() RR {
|
||||||
|
return &PTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||||
|
}
|
||||||
|
func (rr *PX) copy() RR {
|
||||||
|
return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400}
|
||||||
|
}
|
||||||
|
func (rr *RFC3597) copy() RR {
|
||||||
|
return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata}
|
||||||
|
}
|
||||||
|
func (rr *RKEY) copy() RR {
|
||||||
|
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||||
|
}
|
||||||
|
func (rr *RP) copy() RR {
|
||||||
|
return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt}
|
||||||
|
}
|
||||||
|
func (rr *RRSIG) copy() RR {
|
||||||
|
return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
|
||||||
|
}
|
||||||
|
func (rr *RT) copy() RR {
|
||||||
|
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
|
||||||
|
}
|
||||||
|
func (rr *SOA) copy() RR {
|
||||||
|
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
||||||
|
}
|
||||||
|
func (rr *SPF) copy() RR {
|
||||||
|
Txt := make([]string, len(rr.Txt))
|
||||||
|
copy(Txt, rr.Txt)
|
||||||
|
return &SPF{*rr.Hdr.copyHeader(), Txt}
|
||||||
|
}
|
||||||
|
func (rr *SRV) copy() RR {
|
||||||
|
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
|
||||||
|
}
|
||||||
|
func (rr *SSHFP) copy() RR {
|
||||||
|
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
|
||||||
|
}
|
||||||
|
func (rr *TA) copy() RR {
|
||||||
|
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||||
|
}
|
||||||
|
func (rr *TALINK) copy() RR {
|
||||||
|
return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName}
|
||||||
|
}
|
||||||
|
func (rr *TKEY) copy() RR {
|
||||||
|
return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
|
||||||
|
}
|
||||||
|
func (rr *TLSA) copy() RR {
|
||||||
|
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
||||||
|
}
|
||||||
|
func (rr *TSIG) copy() RR {
|
||||||
|
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
||||||
|
}
|
||||||
|
func (rr *TXT) copy() RR {
|
||||||
|
Txt := make([]string, len(rr.Txt))
|
||||||
|
copy(Txt, rr.Txt)
|
||||||
|
return &TXT{*rr.Hdr.copyHeader(), Txt}
|
||||||
|
}
|
||||||
|
func (rr *UID) copy() RR {
|
||||||
|
return &UID{*rr.Hdr.copyHeader(), rr.Uid}
|
||||||
|
}
|
||||||
|
func (rr *UINFO) copy() RR {
|
||||||
|
return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo}
|
||||||
|
}
|
||||||
|
func (rr *URI) copy() RR {
|
||||||
|
return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target}
|
||||||
|
}
|
||||||
|
func (rr *WKS) copy() RR {
|
||||||
|
BitMap := make([]uint16, len(rr.BitMap))
|
||||||
|
copy(BitMap, rr.BitMap)
|
||||||
|
return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, BitMap}
|
||||||
|
}
|
||||||
|
func (rr *X25) copy() RR {
|
||||||
|
return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
|
||||||
|
}
|
||||||
167
vendor/github.com/skynetservices/skydns/cache/cache.go
generated
vendored
Normal file
167
vendor/github.com/skynetservices/skydns/cache/cache.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
// 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
Normal file
31
vendor/github.com/skynetservices/skydns/cache/hit.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// 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
Normal file
186
vendor/github.com/skynetservices/skydns/metrics/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
58
vendor/github.com/skynetservices/skydns/msg/service.go
generated
vendored
58
vendor/github.com/skynetservices/skydns/msg/service.go
generated
vendored
@@ -12,6 +12,14 @@ import (
|
|||||||
"github.com/miekg/dns"
|
"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.
|
// 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
|
// 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.
|
// address (4/6), we will treat it like an IP address.
|
||||||
@@ -29,7 +37,7 @@ type Service struct {
|
|||||||
// the record lives to a DNS name and use this as the srv.Target. When
|
// 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
|
// TargetStrip > 0 we strip the left most TargetStrip labels from the
|
||||||
// DNS name.
|
// DNS name.
|
||||||
TargetStrip int `json:"targetstrip",omitempty"`
|
TargetStrip int `json:"targetstrip,omitempty"`
|
||||||
|
|
||||||
// Group is used to group (or *not* to group) different services
|
// Group is used to group (or *not* to group) different services
|
||||||
// together. Services with an identical Group are returned in the same
|
// together. Services with an identical Group are returned in the same
|
||||||
@@ -42,17 +50,7 @@ type Service struct {
|
|||||||
|
|
||||||
// NewSRV returns a new SRV record based on the Service.
|
// NewSRV returns a new SRV record based on the Service.
|
||||||
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
|
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
|
||||||
host := dns.Fqdn(s.Host)
|
host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
|
||||||
|
|
||||||
offset, end := 0, false
|
|
||||||
for i := 0; i < s.TargetStrip; i++ {
|
|
||||||
offset, end = dns.NextLabel(host, offset)
|
|
||||||
}
|
|
||||||
if end {
|
|
||||||
// We overshot the name, use the orignal one.
|
|
||||||
offset = 0
|
|
||||||
}
|
|
||||||
host = host[offset:]
|
|
||||||
|
|
||||||
return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl},
|
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}
|
Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host}
|
||||||
@@ -60,17 +58,7 @@ func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
|
|||||||
|
|
||||||
// NewMX returns a new MX record based on the Service.
|
// NewMX returns a new MX record based on the Service.
|
||||||
func (s *Service) NewMX(name string) *dns.MX {
|
func (s *Service) NewMX(name string) *dns.MX {
|
||||||
host := dns.Fqdn(s.Host)
|
host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
|
||||||
|
|
||||||
offset, end := 0, false
|
|
||||||
for i := 0; i < s.TargetStrip; i++ {
|
|
||||||
offset, end = dns.NextLabel(host, offset)
|
|
||||||
}
|
|
||||||
if end {
|
|
||||||
// We overshot the name, use the orignal one.
|
|
||||||
offset = 0
|
|
||||||
}
|
|
||||||
host = host[offset:]
|
|
||||||
|
|
||||||
return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl},
|
return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl},
|
||||||
Preference: uint16(s.Priority), Mx: host}
|
Preference: uint16(s.Priority), Mx: host}
|
||||||
@@ -118,10 +106,10 @@ func PathWithWildcard(s string) (string, bool) {
|
|||||||
}
|
}
|
||||||
for i, k := range l {
|
for i, k := range l {
|
||||||
if k == "*" || k == "any" {
|
if k == "*" || k == "any" {
|
||||||
return path.Join(append([]string{"/skydns/"}, l[:i]...)...), true
|
return path.Join(append([]string{"/" + PathPrefix + "/"}, l[:i]...)...), true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return path.Join(append([]string{"/skydns/"}, l...)...), false
|
return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...), false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
|
// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
|
||||||
@@ -131,7 +119,7 @@ func Path(s string) string {
|
|||||||
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||||
l[i], l[j] = l[j], l[i]
|
l[i], l[j] = l[j], l[i]
|
||||||
}
|
}
|
||||||
return path.Join(append([]string{"/skydns/"}, l...)...)
|
return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Domain is the opposite of Path.
|
// Domain is the opposite of Path.
|
||||||
@@ -213,3 +201,21 @@ func split255(s string) []string {
|
|||||||
|
|
||||||
return sx
|
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
Normal file
46
vendor/github.com/skynetservices/skydns/server/backend.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// 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
Normal file
157
vendor/github.com/skynetservices/skydns/server/config.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
// 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, seperated 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
Normal file
177
vendor/github.com/skynetservices/skydns/server/dnssec.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
// 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
Normal file
8
vendor/github.com/skynetservices/skydns/server/doc.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// 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
Normal file
34
vendor/github.com/skynetservices/skydns/server/exchange.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// 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
Normal file
125
vendor/github.com/skynetservices/skydns/server/forwarding.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
// 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 is not equal to success")
|
||||||
|
}
|
||||||
|
// 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
Normal file
17
vendor/github.com/skynetservices/skydns/server/log.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// 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
Normal file
54
vendor/github.com/skynetservices/skydns/server/msg.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// 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
Normal file
155
vendor/github.com/skynetservices/skydns/server/nsec3.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
888
vendor/github.com/skynetservices/skydns/server/server.go
generated
vendored
Normal file
888
vendor/github.com/skynetservices/skydns/server/server.go
generated
vendored
Normal file
@@ -0,0 +1,888 @@
|
|||||||
|
// 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) {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
// 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: %s", 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
Normal file
124
vendor/github.com/skynetservices/skydns/server/stub.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// 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
Normal file
64
vendor/github.com/skynetservices/skydns/singleflight/singleflight.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user