@cryptotaxi247 / kubo / commits / 73c388881

vendored mdns deps

Juan Batiz-Benet committed Apr 21, 2015 at 23:57 UTC 73c38888124a9717d320bf6b90625a14779fd956
205 files changed +29363 -1
Godeps/Godeps.json
+21
@@ -14,6 +14,11 @@
14 "Comment": "null-15",
15 "Rev": "35bc42037350f0078e3c974c6ea690f1926603ab"
16 },
17 + {
18 + "ImportPath": "code.google.com/p/go.net/internal/iana",
19 + "Comment": "null-240",
20 + "Rev": "937a34c9de13c766c814510f76bca091dee06028"
21 + },
22 {
23 "ImportPath": "code.google.com/p/gogoprotobuf/io",
24 "Rev": "6c980277330804e94257ac7ef70a3adbe1641059"
@@ -106,10 +111,22 @@
111 "ImportPath": "github.com/h2so5/utp",
112 "Rev": "654d875bb65e96729678180215cf080fe2810371"
113 },
114 + {
115 + "ImportPath": "github.com/hashicorp/go.net/ipv4",
116 + "Rev": "cbad13bf000d0cbdbc71506b26e94bcc72bbe74d"
117 + },
118 + {
119 + "ImportPath": "github.com/hashicorp/go.net/ipv6",
120 + "Rev": "cbad13bf000d0cbdbc71506b26e94bcc72bbe74d"
121 + },
122 {
123 "ImportPath": "github.com/hashicorp/golang-lru",
124 "Rev": "253b2dc1ca8bae42c3b5b6e53dd2eab1a7551116"
125 },
126 + {
127 + "ImportPath": "github.com/hashicorp/mdns",
128 + "Rev": "e4aba3430cd7360a45a596da8eacff13abb8ae2d"
129 + },
130 {
131 "ImportPath": "github.com/hashicorp/yamux",
132 "Rev": "9feabe6854fadca1abec9cd3bd2a613fe9a34000"
@@ -209,6 +226,10 @@
226 "ImportPath": "github.com/kr/binarydist",
227 "Rev": "9955b0ab8708602d411341e55fffd7e0700f86bd"
228 },
229 + {
230 + "ImportPath": "github.com/miekg/dns",
231 + "Rev": "a76c0a363dd4798064787c742fdf54a593787e91"
232 + },
233 {
234 "ImportPath": "github.com/mitchellh/go-homedir",
235 "Rev": "7d2d8c8a4e078ce3c58736ab521a40b37a504c52"
Godeps/_workspace/src/code.google.com/p/go.net/internal/iana/const.go new
+184
@@ -0,0 +1,184 @@
1 +// go generate gen.go
2 +// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3 +
4 +// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
5 +package iana
6 +
7 +// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25
8 +const (
9 + DiffServCS0 = 0x0 // CS0
10 + DiffServCS1 = 0x20 // CS1
11 + DiffServCS2 = 0x40 // CS2
12 + DiffServCS3 = 0x60 // CS3
13 + DiffServCS4 = 0x80 // CS4
14 + DiffServCS5 = 0xa0 // CS5
15 + DiffServCS6 = 0xc0 // CS6
16 + DiffServCS7 = 0xe0 // CS7
17 + DiffServAF11 = 0x28 // AF11
18 + DiffServAF12 = 0x30 // AF12
19 + DiffServAF13 = 0x38 // AF13
20 + DiffServAF21 = 0x48 // AF21
21 + DiffServAF22 = 0x50 // AF22
22 + DiffServAF23 = 0x58 // AF23
23 + DiffServAF31 = 0x68 // AF31
24 + DiffServAF32 = 0x70 // AF32
25 + DiffServAF33 = 0x78 // AF33
26 + DiffServAF41 = 0x88 // AF41
27 + DiffServAF42 = 0x90 // AF42
28 + DiffServAF43 = 0x98 // AF43
29 + DiffServEFPHB = 0xb8 // EF PHB
30 + DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
31 +)
32 +
33 +// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
34 +const (
35 + NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
36 + ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
37 + ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
38 + CongestionExperienced = 0x3 // CE (Congestion Experienced)
39 +)
40 +
41 +// Protocol Numbers, Updated: 2014-08-12
42 +const (
43 + ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
44 + ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
45 + ProtocolICMP = 1 // Internet Control Message
46 + ProtocolIGMP = 2 // Internet Group Management
47 + ProtocolGGP = 3 // Gateway-to-Gateway
48 + ProtocolIPv4 = 4 // IPv4 encapsulation
49 + ProtocolST = 5 // Stream
50 + ProtocolTCP = 6 // Transmission Control
51 + ProtocolCBT = 7 // CBT
52 + ProtocolEGP = 8 // Exterior Gateway Protocol
53 + ProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP)
54 + ProtocolBBNRCCMON = 10 // BBN RCC Monitoring
55 + ProtocolNVPII = 11 // Network Voice Protocol
56 + ProtocolPUP = 12 // PUP
57 + ProtocolARGUS = 13 // ARGUS
58 + ProtocolEMCON = 14 // EMCON
59 + ProtocolXNET = 15 // Cross Net Debugger
60 + ProtocolCHAOS = 16 // Chaos
61 + ProtocolUDP = 17 // User Datagram
62 + ProtocolMUX = 18 // Multiplexing
63 + ProtocolDCNMEAS = 19 // DCN Measurement Subsystems
64 + ProtocolHMP = 20 // Host Monitoring
65 + ProtocolPRM = 21 // Packet Radio Measurement
66 + ProtocolXNSIDP = 22 // XEROX NS IDP
67 + ProtocolTRUNK1 = 23 // Trunk-1
68 + ProtocolTRUNK2 = 24 // Trunk-2
69 + ProtocolLEAF1 = 25 // Leaf-1
70 + ProtocolLEAF2 = 26 // Leaf-2
71 + ProtocolRDP = 27 // Reliable Data Protocol
72 + ProtocolIRTP = 28 // Internet Reliable Transaction
73 + ProtocolISOTP4 = 29 // ISO Transport Protocol Class 4
74 + ProtocolNETBLT = 30 // Bulk Data Transfer Protocol
75 + ProtocolMFENSP = 31 // MFE Network Services Protocol
76 + ProtocolMERITINP = 32 // MERIT Internodal Protocol
77 + ProtocolDCCP = 33 // Datagram Congestion Control Protocol
78 + Protocol3PC = 34 // Third Party Connect Protocol
79 + ProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol
80 + ProtocolXTP = 36 // XTP
81 + ProtocolDDP = 37 // Datagram Delivery Protocol
82 + ProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto
83 + ProtocolTPPP = 39 // TP++ Transport Protocol
84 + ProtocolIL = 40 // IL Transport Protocol
85 + ProtocolIPv6 = 41 // IPv6 encapsulation
86 + ProtocolSDRP = 42 // Source Demand Routing Protocol
87 + ProtocolIPv6Route = 43 // Routing Header for IPv6
88 + ProtocolIPv6Frag = 44 // Fragment Header for IPv6
89 + ProtocolIDRP = 45 // Inter-Domain Routing Protocol
90 + ProtocolRSVP = 46 // Reservation Protocol
91 + ProtocolGRE = 47 // Generic Routing Encapsulation
92 + ProtocolDSR = 48 // Dynamic Source Routing Protocol
93 + ProtocolBNA = 49 // BNA
94 + ProtocolESP = 50 // Encap Security Payload
95 + ProtocolAH = 51 // Authentication Header
96 + ProtocolINLSP = 52 // Integrated Net Layer Security TUBA
97 + ProtocolSWIPE = 53 // IP with Encryption
98 + ProtocolNARP = 54 // NBMA Address Resolution Protocol
99 + ProtocolMOBILE = 55 // IP Mobility
100 + ProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management
101 + ProtocolSKIP = 57 // SKIP
102 + ProtocolIPv6ICMP = 58 // ICMP for IPv6
103 + ProtocolIPv6NoNxt = 59 // No Next Header for IPv6
104 + ProtocolIPv6Opts = 60 // Destination Options for IPv6
105 + ProtocolCFTP = 62 // CFTP
106 + ProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK
107 + ProtocolKRYPTOLAN = 65 // Kryptolan
108 + ProtocolRVD = 66 // MIT Remote Virtual Disk Protocol
109 + ProtocolIPPC = 67 // Internet Pluribus Packet Core
110 + ProtocolSATMON = 69 // SATNET Monitoring
111 + ProtocolVISA = 70 // VISA Protocol
112 + ProtocolIPCV = 71 // Internet Packet Core Utility
113 + ProtocolCPNX = 72 // Computer Protocol Network Executive
114 + ProtocolCPHB = 73 // Computer Protocol Heart Beat
115 + ProtocolWSN = 74 // Wang Span Network
116 + ProtocolPVP = 75 // Packet Video Protocol
117 + ProtocolBRSATMON = 76 // Backroom SATNET Monitoring
118 + ProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary
119 + ProtocolWBMON = 78 // WIDEBAND Monitoring
120 + ProtocolWBEXPAK = 79 // WIDEBAND EXPAK
121 + ProtocolISOIP = 80 // ISO Internet Protocol
122 + ProtocolVMTP = 81 // VMTP
123 + ProtocolSECUREVMTP = 82 // SECURE-VMTP
124 + ProtocolVINES = 83 // VINES
125 + ProtocolTTP = 84 // Transaction Transport Protocol
126 + ProtocolIPTM = 84 // Internet Protocol Traffic Manager
127 + ProtocolNSFNETIGP = 85 // NSFNET-IGP
128 + ProtocolDGP = 86 // Dissimilar Gateway Protocol
129 + ProtocolTCF = 87 // TCF
130 + ProtocolEIGRP = 88 // EIGRP
131 + ProtocolOSPFIGP = 89 // OSPFIGP
132 + ProtocolSpriteRPC = 90 // Sprite RPC Protocol
133 + ProtocolLARP = 91 // Locus Address Resolution Protocol
134 + ProtocolMTP = 92 // Multicast Transport Protocol
135 + ProtocolAX25 = 93 // AX.25 Frames
136 + ProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol
137 + ProtocolMICP = 95 // Mobile Internetworking Control Pro.
138 + ProtocolSCCSP = 96 // Semaphore Communications Sec. Pro.
139 + ProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation
140 + ProtocolENCAP = 98 // Encapsulation Header
141 + ProtocolGMTP = 100 // GMTP
142 + ProtocolIFMP = 101 // Ipsilon Flow Management Protocol
143 + ProtocolPNNI = 102 // PNNI over IP
144 + ProtocolPIM = 103 // Protocol Independent Multicast
145 + ProtocolARIS = 104 // ARIS
146 + ProtocolSCPS = 105 // SCPS
147 + ProtocolQNX = 106 // QNX
148 + ProtocolAN = 107 // Active Networks
149 + ProtocolIPComp = 108 // IP Payload Compression Protocol
150 + ProtocolSNP = 109 // Sitara Networks Protocol
151 + ProtocolCompaqPeer = 110 // Compaq Peer Protocol
152 + ProtocolIPXinIP = 111 // IPX in IP
153 + ProtocolVRRP = 112 // Virtual Router Redundancy Protocol
154 + ProtocolPGM = 113 // PGM Reliable Transport Protocol
155 + ProtocolL2TP = 115 // Layer Two Tunneling Protocol
156 + ProtocolDDX = 116 // D-II Data Exchange (DDX)
157 + ProtocolIATP = 117 // Interactive Agent Transfer Protocol
158 + ProtocolSTP = 118 // Schedule Transfer Protocol
159 + ProtocolSRP = 119 // SpectraLink Radio Protocol
160 + ProtocolUTI = 120 // UTI
161 + ProtocolSMP = 121 // Simple Message Protocol
162 + ProtocolSM = 122 // Simple Multicast Protocol
163 + ProtocolPTP = 123 // Performance Transparency Protocol
164 + ProtocolISIS = 124 // ISIS over IPv4
165 + ProtocolFIRE = 125 // FIRE
166 + ProtocolCRTP = 126 // Combat Radio Transport Protocol
167 + ProtocolCRUDP = 127 // Combat Radio User Datagram
168 + ProtocolSSCOPMCE = 128 // SSCOPMCE
169 + ProtocolIPLT = 129 // IPLT
170 + ProtocolSPS = 130 // Secure Packet Shield
171 + ProtocolPIPE = 131 // Private IP Encapsulation within IP
172 + ProtocolSCTP = 132 // Stream Control Transmission Protocol
173 + ProtocolFC = 133 // Fibre Channel
174 + ProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE
175 + ProtocolMobilityHeader = 135 // Mobility Header
176 + ProtocolUDPLite = 136 // UDPLite
177 + ProtocolMPLSinIP = 137 // MPLS-in-IP
178 + ProtocolMANET = 138 // MANET Protocols
179 + ProtocolHIP = 139 // Host Identity Protocol
180 + ProtocolShim6 = 140 // Shim6 Protocol
181 + ProtocolWESP = 141 // Wrapped Encapsulating Security Payload
182 + ProtocolROHC = 142 // Robust Header Compression
183 + ProtocolReserved = 255 // Reserved
184 +)
Godeps/_workspace/src/code.google.com/p/go.net/internal/iana/gen.go new
+289
@@ -0,0 +1,289 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +//go:generate go run gen.go
8 +
9 +// This program generates internet protocol constants and tables by
10 +// reading IANA protocol registries.
11 +package main
12 +
13 +import (
14 + "bytes"
15 + "encoding/xml"
16 + "fmt"
17 + "go/format"
18 + "io"
19 + "io/ioutil"
20 + "net/http"
21 + "os"
22 + "strconv"
23 + "strings"
24 +)
25 +
26 +var registries = []struct {
27 + url string
28 + parse func(io.Writer, io.Reader) error
29 +}{
30 + {
31 + "http://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
32 + parseDSCPRegistry,
33 + },
34 + {
35 + "http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
36 + parseTOSTCByte,
37 + },
38 + {
39 + "http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
40 + parseProtocolNumbers,
41 + },
42 +}
43 +
44 +func main() {
45 + var bb bytes.Buffer
46 + fmt.Fprintf(&bb, "// go generate gen.go\n")
47 + fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
48 + fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
49 + fmt.Fprintf(&bb, "package iana\n\n")
50 + for _, r := range registries {
51 + resp, err := http.Get(r.url)
52 + if err != nil {
53 + fmt.Fprintln(os.Stderr, err)
54 + os.Exit(1)
55 + }
56 + defer resp.Body.Close()
57 + if resp.StatusCode != http.StatusOK {
58 + fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
59 + os.Exit(1)
60 + }
61 + if err := r.parse(&bb, resp.Body); err != nil {
62 + fmt.Fprintln(os.Stderr, err)
63 + os.Exit(1)
64 + }
65 + fmt.Fprintf(&bb, "\n")
66 + }
67 + b, err := format.Source(bb.Bytes())
68 + if err != nil {
69 + fmt.Fprintln(os.Stderr, err)
70 + os.Exit(1)
71 + }
72 + if err := ioutil.WriteFile("const.go", b, 0644); err != nil {
73 + fmt.Fprintln(os.Stderr, err)
74 + os.Exit(1)
75 + }
76 +}
77 +
78 +func parseDSCPRegistry(w io.Writer, r io.Reader) error {
79 + dec := xml.NewDecoder(r)
80 + var dr dscpRegistry
81 + if err := dec.Decode(&dr); err != nil {
82 + return err
83 + }
84 + drs := dr.escape()
85 + fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
86 + fmt.Fprintf(w, "const (\n")
87 + for _, dr := range drs {
88 + fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value)
89 + fmt.Fprintf(w, "// %s\n", dr.OrigName)
90 + }
91 + fmt.Fprintf(w, ")\n")
92 + return nil
93 +}
94 +
95 +type dscpRegistry struct {
96 + XMLName xml.Name `xml:"registry"`
97 + Title string `xml:"title"`
98 + Updated string `xml:"updated"`
99 + Note string `xml:"note"`
100 + RegTitle string `xml:"registry>title"`
101 + PoolRecords []struct {
102 + Name string `xml:"name"`
103 + Space string `xml:"space"`
104 + } `xml:"registry>record"`
105 + Records []struct {
106 + Name string `xml:"name"`
107 + Space string `xml:"space"`
108 + } `xml:"registry>registry>record"`
109 +}
110 +
111 +type canonDSCPRecord struct {
112 + OrigName string
113 + Name string
114 + Value int
115 +}
116 +
117 +func (drr *dscpRegistry) escape() []canonDSCPRecord {
118 + drs := make([]canonDSCPRecord, len(drr.Records))
119 + sr := strings.NewReplacer(
120 + "+", "",
121 + "-", "",
122 + "/", "",
123 + ".", "",
124 + " ", "",
125 + )
126 + for i, dr := range drr.Records {
127 + s := strings.TrimSpace(dr.Name)
128 + drs[i].OrigName = s
129 + drs[i].Name = sr.Replace(s)
130 + n, err := strconv.ParseUint(dr.Space, 2, 8)
131 + if err != nil {
132 + continue
133 + }
134 + drs[i].Value = int(n) << 2
135 + }
136 + return drs
137 +}
138 +
139 +func parseTOSTCByte(w io.Writer, r io.Reader) error {
140 + dec := xml.NewDecoder(r)
141 + var ttb tosTCByte
142 + if err := dec.Decode(&ttb); err != nil {
143 + return err
144 + }
145 + trs := ttb.escape()
146 + fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated)
147 + fmt.Fprintf(w, "const (\n")
148 + for _, tr := range trs {
149 + fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value)
150 + fmt.Fprintf(w, "// %s\n", tr.OrigKeyword)
151 + }
152 + fmt.Fprintf(w, ")\n")
153 + return nil
154 +}
155 +
156 +type tosTCByte struct {
157 + XMLName xml.Name `xml:"registry"`
158 + Title string `xml:"title"`
159 + Updated string `xml:"updated"`
160 + Note string `xml:"note"`
161 + RegTitle string `xml:"registry>title"`
162 + Records []struct {
163 + Binary string `xml:"binary"`
164 + Keyword string `xml:"keyword"`
165 + } `xml:"registry>record"`
166 +}
167 +
168 +type canonTOSTCByteRecord struct {
169 + OrigKeyword string
170 + Keyword string
171 + Value int
172 +}
173 +
174 +func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
175 + trs := make([]canonTOSTCByteRecord, len(ttb.Records))
176 + sr := strings.NewReplacer(
177 + "Capable", "",
178 + "(", "",
179 + ")", "",
180 + "+", "",
181 + "-", "",
182 + "/", "",
183 + ".", "",
184 + " ", "",
185 + )
186 + for i, tr := range ttb.Records {
187 + s := strings.TrimSpace(tr.Keyword)
188 + trs[i].OrigKeyword = s
189 + ss := strings.Split(s, " ")
190 + if len(ss) > 1 {
191 + trs[i].Keyword = strings.Join(ss[1:], " ")
192 + } else {
193 + trs[i].Keyword = ss[0]
194 + }
195 + trs[i].Keyword = sr.Replace(trs[i].Keyword)
196 + n, err := strconv.ParseUint(tr.Binary, 2, 8)
197 + if err != nil {
198 + continue
199 + }
200 + trs[i].Value = int(n)
201 + }
202 + return trs
203 +}
204 +
205 +func parseProtocolNumbers(w io.Writer, r io.Reader) error {
206 + dec := xml.NewDecoder(r)
207 + var pn protocolNumbers
208 + if err := dec.Decode(&pn); err != nil {
209 + return err
210 + }
211 + prs := pn.escape()
212 + prs = append([]canonProtocolRecord{{
213 + Name: "IP",
214 + Descr: "IPv4 encapsulation, pseudo protocol number",
215 + Value: 0,
216 + }}, prs...)
217 + fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated)
218 + fmt.Fprintf(w, "const (\n")
219 + for _, pr := range prs {
220 + if pr.Name == "" {
221 + continue
222 + }
223 + fmt.Fprintf(w, "Protocol%s = %d", pr.Name, pr.Value)
224 + s := pr.Descr
225 + if s == "" {
226 + s = pr.OrigName
227 + }
228 + fmt.Fprintf(w, "// %s\n", s)
229 + }
230 + fmt.Fprintf(w, ")\n")
231 + return nil
232 +}
233 +
234 +type protocolNumbers struct {
235 + XMLName xml.Name `xml:"registry"`
236 + Title string `xml:"title"`
237 + Updated string `xml:"updated"`
238 + RegTitle string `xml:"registry>title"`
239 + Note string `xml:"registry>note"`
240 + Records []struct {
241 + Value string `xml:"value"`
242 + Name string `xml:"name"`
243 + Descr string `xml:"description"`
244 + } `xml:"registry>record"`
245 +}
246 +
247 +type canonProtocolRecord struct {
248 + OrigName string
249 + Name string
250 + Descr string
251 + Value int
252 +}
253 +
254 +func (pn *protocolNumbers) escape() []canonProtocolRecord {
255 + prs := make([]canonProtocolRecord, len(pn.Records))
256 + sr := strings.NewReplacer(
257 + "-in-", "in",
258 + "-within-", "within",
259 + "-over-", "over",
260 + "+", "P",
261 + "-", "",
262 + "/", "",
263 + ".", "",
264 + " ", "",
265 + )
266 + for i, pr := range pn.Records {
267 + prs[i].OrigName = pr.Name
268 + s := strings.TrimSpace(pr.Name)
269 + switch pr.Name {
270 + case "ISIS over IPv4":
271 + prs[i].Name = "ISIS"
272 + case "manet":
273 + prs[i].Name = "MANET"
274 + default:
275 + prs[i].Name = sr.Replace(s)
276 + }
277 + ss := strings.Split(pr.Descr, "\n")
278 + for i := range ss {
279 + ss[i] = strings.TrimSpace(ss[i])
280 + }
281 + if len(ss) > 1 {
282 + prs[i].Descr = strings.Join(ss, " ")
283 + } else {
284 + prs[i].Descr = ss[0]
285 + }
286 + prs[i].Value, _ = strconv.Atoi(pr.Value)
287 + }
288 + return prs
289 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/control.go new
+70
@@ -0,0 +1,70 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "fmt"
9 + "net"
10 + "sync"
11 +)
12 +
13 +type rawOpt struct {
14 + sync.RWMutex
15 + cflags ControlFlags
16 +}
17 +
18 +func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
19 +func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
20 +func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
21 +
22 +type ControlFlags uint
23 +
24 +const (
25 + FlagTTL ControlFlags = 1 << iota // pass the TTL on the received packet
26 + FlagSrc // pass the source address on the received packet
27 + FlagDst // pass the destination address on the received packet
28 + FlagInterface // pass the interface index on the received packet
29 +)
30 +
31 +// A ControlMessage represents per packet basis IP-level socket options.
32 +type ControlMessage struct {
33 + // Receiving socket options: SetControlMessage allows to
34 + // receive the options from the protocol stack using ReadFrom
35 + // method of PacketConn or RawConn.
36 + //
37 + // Specifying socket options: ControlMessage for WriteTo
38 + // method of PacketConn or RawConn allows to send the options
39 + // to the protocol stack.
40 + //
41 + TTL int // time-to-live, receiving only
42 + Src net.IP // source address, specifying only
43 + Dst net.IP // destination address, receiving only
44 + IfIndex int // interface index, must be 1 <= value when specifying
45 +}
46 +
47 +func (cm *ControlMessage) String() string {
48 + if cm == nil {
49 + return "<nil>"
50 + }
51 + return fmt.Sprintf("ttl: %v, src: %v, dst: %v, ifindex: %v", cm.TTL, cm.Src, cm.Dst, cm.IfIndex)
52 +}
53 +
54 +// Ancillary data socket options
55 +const (
56 + ctlTTL = iota // header field
57 + ctlSrc // header field
58 + ctlDst // header field
59 + ctlInterface // inbound or outbound interface
60 + ctlPacketInfo // inbound or outbound packet path
61 + ctlMax
62 +)
63 +
64 +// A ctlOpt represents a binding for ancillary data socket option.
65 +type ctlOpt struct {
66 + name int // option name, must be equal or greater than 1
67 + length int // option length
68 + marshal func([]byte, *ControlMessage) []byte
69 + parse func(*ControlMessage, []byte)
70 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/control_bsd.go new
+40
@@ -0,0 +1,40 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd netbsd openbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "syscall"
12 + "unsafe"
13 +
14 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
15 +)
16 +
17 +func marshalDst(b []byte, cm *ControlMessage) []byte {
18 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
19 + m.Level = iana.ProtocolIP
20 + m.Type = sysIP_RECVDSTADDR
21 + m.SetLen(syscall.CmsgLen(net.IPv4len))
22 + return b[syscall.CmsgSpace(net.IPv4len):]
23 +}
24 +
25 +func parseDst(cm *ControlMessage, b []byte) {
26 + cm.Dst = b[:net.IPv4len]
27 +}
28 +
29 +func marshalInterface(b []byte, cm *ControlMessage) []byte {
30 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
31 + m.Level = iana.ProtocolIP
32 + m.Type = sysIP_RECVIF
33 + m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
34 + return b[syscall.CmsgSpace(syscall.SizeofSockaddrDatalink):]
35 +}
36 +
37 +func parseInterface(cm *ControlMessage, b []byte) {
38 + sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&b[0]))
39 + cm.IfIndex = int(sadl.Index)
40 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/control_pktinfo.go new
+37
@@ -0,0 +1,37 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin linux
6 +
7 +package ipv4
8 +
9 +import (
10 + "syscall"
11 + "unsafe"
12 +
13 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
14 +)
15 +
16 +func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
17 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
18 + m.Level = iana.ProtocolIP
19 + m.Type = sysIP_PKTINFO
20 + m.SetLen(syscall.CmsgLen(sysSizeofInetPktinfo))
21 + if cm != nil {
22 + pi := (*sysInetPktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
23 + if ip := cm.Src.To4(); ip != nil {
24 + copy(pi.Spec_dst[:], ip)
25 + }
26 + if cm.IfIndex != 0 {
27 + pi.setIfindex(cm.IfIndex)
28 + }
29 + }
30 + return b[syscall.CmsgSpace(sysSizeofInetPktinfo):]
31 +}
32 +
33 +func parsePacketInfo(cm *ControlMessage, b []byte) {
34 + pi := (*sysInetPktinfo)(unsafe.Pointer(&b[0]))
35 + cm.IfIndex = int(pi.Ifindex)
36 + cm.Dst = pi.Addr[:]
37 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/control_stub.go new
+27
@@ -0,0 +1,27 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv4
8 +
9 +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
10 + // TODO(mikio): Implement this
11 + return errOpNoSupport
12 +}
13 +
14 +func newControlMessage(opt *rawOpt) []byte {
15 + // TODO(mikio): Implement this
16 + return nil
17 +}
18 +
19 +func parseControlMessage(b []byte) (*ControlMessage, error) {
20 + // TODO(mikio): Implement this
21 + return nil, errOpNoSupport
22 +}
23 +
24 +func marshalControlMessage(cm *ControlMessage) []byte {
25 + // TODO(mikio): Implement this
26 + return nil
27 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/control_unix.go new
+166
@@ -0,0 +1,166 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "os"
11 + "syscall"
12 + "unsafe"
13 +
14 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
15 +)
16 +
17 +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
18 + opt.Lock()
19 + defer opt.Unlock()
20 + if cf&FlagTTL != 0 {
21 + if err := setInt(fd, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil {
22 + return err
23 + }
24 + if on {
25 + opt.set(FlagTTL)
26 + } else {
27 + opt.clear(FlagTTL)
28 + }
29 + }
30 + if sockOpts[ssoPacketInfo].name > 0 {
31 + if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
32 + if err := setInt(fd, &sockOpts[ssoPacketInfo], boolint(on)); err != nil {
33 + return err
34 + }
35 + if on {
36 + opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
37 + } else {
38 + opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
39 + }
40 + }
41 + } else {
42 + if cf&FlagDst != 0 {
43 + if err := setInt(fd, &sockOpts[ssoReceiveDst], boolint(on)); err != nil {
44 + return err
45 + }
46 + if on {
47 + opt.set(FlagDst)
48 + } else {
49 + opt.clear(FlagDst)
50 + }
51 + }
52 + if cf&FlagInterface != 0 {
53 + if err := setInt(fd, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil {
54 + return err
55 + }
56 + if on {
57 + opt.set(FlagInterface)
58 + } else {
59 + opt.clear(FlagInterface)
60 + }
61 + }
62 + }
63 + return nil
64 +}
65 +
66 +func newControlMessage(opt *rawOpt) (oob []byte) {
67 + opt.RLock()
68 + var l int
69 + if opt.isset(FlagTTL) {
70 + l += syscall.CmsgSpace(ctlOpts[ctlTTL].length)
71 + }
72 + if ctlOpts[ctlPacketInfo].name > 0 {
73 + if opt.isset(FlagSrc | FlagDst | FlagInterface) {
74 + l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
75 + }
76 + } else {
77 + if opt.isset(FlagDst) {
78 + l += syscall.CmsgSpace(ctlOpts[ctlDst].length)
79 + }
80 + if opt.isset(FlagInterface) {
81 + l += syscall.CmsgSpace(ctlOpts[ctlInterface].length)
82 + }
83 + }
84 + if l > 0 {
85 + oob = make([]byte, l)
86 + b := oob
87 + if opt.isset(FlagTTL) {
88 + b = ctlOpts[ctlTTL].marshal(b, nil)
89 + }
90 + if ctlOpts[ctlPacketInfo].name > 0 {
91 + if opt.isset(FlagSrc | FlagDst | FlagInterface) {
92 + b = ctlOpts[ctlPacketInfo].marshal(b, nil)
93 + }
94 + } else {
95 + if opt.isset(FlagDst) {
96 + b = ctlOpts[ctlDst].marshal(b, nil)
97 + }
98 + if opt.isset(FlagInterface) {
99 + b = ctlOpts[ctlInterface].marshal(b, nil)
100 + }
101 + }
102 + }
103 + opt.RUnlock()
104 + return
105 +}
106 +
107 +func parseControlMessage(b []byte) (*ControlMessage, error) {
108 + if len(b) == 0 {
109 + return nil, nil
110 + }
111 + cmsgs, err := syscall.ParseSocketControlMessage(b)
112 + if err != nil {
113 + return nil, os.NewSyscallError("parse socket control message", err)
114 + }
115 + cm := &ControlMessage{}
116 + for _, m := range cmsgs {
117 + if m.Header.Level != iana.ProtocolIP {
118 + continue
119 + }
120 + switch int(m.Header.Type) {
121 + case ctlOpts[ctlTTL].name:
122 + ctlOpts[ctlTTL].parse(cm, m.Data[:])
123 + case ctlOpts[ctlDst].name:
124 + ctlOpts[ctlDst].parse(cm, m.Data[:])
125 + case ctlOpts[ctlInterface].name:
126 + ctlOpts[ctlInterface].parse(cm, m.Data[:])
127 + case ctlOpts[ctlPacketInfo].name:
128 + ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
129 + }
130 + }
131 + return cm, nil
132 +}
133 +
134 +func marshalControlMessage(cm *ControlMessage) (oob []byte) {
135 + if cm == nil {
136 + return nil
137 + }
138 + var l int
139 + if ctlOpts[ctlPacketInfo].name > 0 {
140 + if cm.Src.To4() != nil || cm.IfIndex != 0 {
141 + l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
142 + }
143 + }
144 + if l > 0 {
145 + oob = make([]byte, l)
146 + b := oob
147 + if ctlOpts[ctlPacketInfo].name > 0 {
148 + if cm.Src.To4() != nil || cm.IfIndex != 0 {
149 + b = ctlOpts[ctlPacketInfo].marshal(b, cm)
150 + }
151 + }
152 + }
153 + return
154 +}
155 +
156 +func marshalTTL(b []byte, cm *ControlMessage) []byte {
157 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
158 + m.Level = iana.ProtocolIP
159 + m.Type = sysIP_RECVTTL
160 + m.SetLen(syscall.CmsgLen(1))
161 + return b[syscall.CmsgSpace(1):]
162 +}
163 +
164 +func parseTTL(cm *ControlMessage, b []byte) {
165 + cm.TTL = int(*(*byte)(unsafe.Pointer(&b[:1][0])))
166 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/control_windows.go new
+27
@@ -0,0 +1,27 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import "syscall"
8 +
9 +func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error {
10 + // TODO(mikio): Implement this
11 + return syscall.EWINDOWS
12 +}
13 +
14 +func newControlMessage(opt *rawOpt) []byte {
15 + // TODO(mikio): Implement this
16 + return nil
17 +}
18 +
19 +func parseControlMessage(b []byte) (*ControlMessage, error) {
20 + // TODO(mikio): Implement this
21 + return nil, syscall.EWINDOWS
22 +}
23 +
24 +func marshalControlMessage(cm *ControlMessage) []byte {
25 + // TODO(mikio): Implement this
26 + return nil
27 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_darwin.go new
+57
@@ -0,0 +1,57 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <netinet/in.h>
13 +*/
14 +import "C"
15 +
16 +const (
17 + sysIP_OPTIONS = C.IP_OPTIONS
18 + sysIP_HDRINCL = C.IP_HDRINCL
19 + sysIP_TOS = C.IP_TOS
20 + sysIP_TTL = C.IP_TTL
21 + sysIP_RECVOPTS = C.IP_RECVOPTS
22 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
23 + sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
24 + sysIP_RETOPTS = C.IP_RETOPTS
25 + sysIP_RECVIF = C.IP_RECVIF
26 + sysIP_STRIPHDR = C.IP_STRIPHDR
27 + sysIP_RECVTTL = C.IP_RECVTTL
28 + sysIP_BOUND_IF = C.IP_BOUND_IF
29 + sysIP_PKTINFO = C.IP_PKTINFO
30 + sysIP_RECVPKTINFO = C.IP_RECVPKTINFO
31 +
32 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
33 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
34 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
35 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
36 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
37 + sysIP_MULTICAST_VIF = C.IP_MULTICAST_VIF
38 + sysIP_MULTICAST_IFINDEX = C.IP_MULTICAST_IFINDEX
39 + sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP
40 + sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP
41 + sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE
42 + sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE
43 +
44 + sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
45 +
46 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
47 + sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn
48 + sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
49 +)
50 +
51 +type sysInetPktinfo C.struct_in_pktinfo
52 +
53 +type sysIPMreq C.struct_ip_mreq
54 +
55 +type sysIPMreqn C.struct_ip_mreqn
56 +
57 +type sysIPMreqSource C.struct_ip_mreq_source
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_dragonfly.go new
+38
@@ -0,0 +1,38 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <netinet/in.h>
13 +*/
14 +import "C"
15 +
16 +const (
17 + sysIP_OPTIONS = C.IP_OPTIONS
18 + sysIP_HDRINCL = C.IP_HDRINCL
19 + sysIP_TOS = C.IP_TOS
20 + sysIP_TTL = C.IP_TTL
21 + sysIP_RECVOPTS = C.IP_RECVOPTS
22 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
23 + sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
24 + sysIP_RETOPTS = C.IP_RETOPTS
25 + sysIP_RECVIF = C.IP_RECVIF
26 + sysIP_RECVTTL = C.IP_RECVTTL
27 +
28 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
29 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
30 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
31 + sysIP_MULTICAST_VIF = C.IP_MULTICAST_VIF
32 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
33 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
34 +
35 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
36 +)
37 +
38 +type sysIPMreq C.struct_ip_mreq
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_freebsd.go new
+54
@@ -0,0 +1,54 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <netinet/in.h>
13 +*/
14 +import "C"
15 +
16 +const (
17 + sysIP_OPTIONS = C.IP_OPTIONS
18 + sysIP_HDRINCL = C.IP_HDRINCL
19 + sysIP_TOS = C.IP_TOS
20 + sysIP_TTL = C.IP_TTL
21 + sysIP_RECVOPTS = C.IP_RECVOPTS
22 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
23 + sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
24 + sysIP_SENDSRCADDR = C.IP_SENDSRCADDR
25 + sysIP_RETOPTS = C.IP_RETOPTS
26 + sysIP_RECVIF = C.IP_RECVIF
27 + sysIP_ONESBCAST = C.IP_ONESBCAST
28 + sysIP_BINDANY = C.IP_BINDANY
29 + sysIP_RECVTTL = C.IP_RECVTTL
30 + sysIP_MINTTL = C.IP_MINTTL
31 + sysIP_DONTFRAG = C.IP_DONTFRAG
32 + sysIP_RECVTOS = C.IP_RECVTOS
33 +
34 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
35 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
36 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
37 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
38 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
39 + sysIP_MULTICAST_VIF = C.IP_MULTICAST_VIF
40 + sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP
41 + sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP
42 + sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE
43 + sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE
44 +
45 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
46 + sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn
47 + sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
48 +)
49 +
50 +type sysIPMreq C.struct_ip_mreq
51 +
52 +type sysIPMreqn C.struct_ip_mreqn
53 +
54 +type sysIPMreqSource C.struct_ip_mreq_source
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_linux.go new
+82
@@ -0,0 +1,82 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <linux/errqueue.h>
13 +#include <linux/in.h>
14 +*/
15 +import "C"
16 +
17 +const (
18 + sysIP_TOS = C.IP_TOS
19 + sysIP_TTL = C.IP_TTL
20 + sysIP_HDRINCL = C.IP_HDRINCL
21 + sysIP_OPTIONS = C.IP_OPTIONS
22 + sysIP_ROUTER_ALERT = C.IP_ROUTER_ALERT
23 + sysIP_RECVOPTS = C.IP_RECVOPTS
24 + sysIP_RETOPTS = C.IP_RETOPTS
25 + sysIP_PKTINFO = C.IP_PKTINFO
26 + sysIP_PKTOPTIONS = C.IP_PKTOPTIONS
27 + sysIP_MTU_DISCOVER = C.IP_MTU_DISCOVER
28 + sysIP_RECVERR = C.IP_RECVERR
29 + sysIP_RECVTTL = C.IP_RECVTTL
30 + sysIP_RECVTOS = C.IP_RECVTOS
31 + sysIP_MTU = C.IP_MTU
32 + sysIP_FREEBIND = C.IP_FREEBIND
33 + sysIP_TRANSPARENT = C.IP_TRANSPARENT
34 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
35 + sysIP_ORIGDSTADDR = C.IP_ORIGDSTADDR
36 + sysIP_RECVORIGDSTADDR = C.IP_RECVORIGDSTADDR
37 + sysIP_MINTTL = C.IP_MINTTL
38 + sysIP_NODEFRAG = C.IP_NODEFRAG
39 + sysIP_UNICAST_IF = C.IP_UNICAST_IF
40 +
41 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
42 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
43 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
44 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
45 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
46 + sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE
47 + sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE
48 + sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP
49 + sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP
50 + sysIP_MULTICAST_ALL = C.IP_MULTICAST_ALL
51 +
52 + sysIP_PMTUDISC_DONT = C.IP_PMTUDISC_DONT
53 + sysIP_PMTUDISC_WANT = C.IP_PMTUDISC_WANT
54 + sysIP_PMTUDISC_DO = C.IP_PMTUDISC_DO
55 + sysIP_PMTUDISC_PROBE = C.IP_PMTUDISC_PROBE
56 + sysIP_PMTUDISC_INTERFACE = C.IP_PMTUDISC_INTERFACE
57 + sysIP_PMTUDISC_OMIT = C.IP_PMTUDISC_OMIT
58 +
59 + sysSO_EE_ORIGIN_NONE = C.SO_EE_ORIGIN_NONE
60 + sysSO_EE_ORIGIN_LOCAL = C.SO_EE_ORIGIN_LOCAL
61 + sysSO_EE_ORIGIN_ICMP = C.SO_EE_ORIGIN_ICMP
62 + sysSO_EE_ORIGIN_ICMP6 = C.SO_EE_ORIGIN_ICMP6
63 + sysSO_EE_ORIGIN_TXSTATUS = C.SO_EE_ORIGIN_TXSTATUS
64 + sysSO_EE_ORIGIN_TIMESTAMPING = C.SO_EE_ORIGIN_TIMESTAMPING
65 +
66 + sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
67 + sysSizeofSockExtendedErr = C.sizeof_struct_sock_extended_err
68 +
69 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
70 + sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn
71 + sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
72 +)
73 +
74 +type sysInetPktinfo C.struct_in_pktinfo
75 +
76 +type sysSockExtendedErr C.struct_sock_extended_err
77 +
78 +type sysIPMreq C.struct_ip_mreq
79 +
80 +type sysIPMreqn C.struct_ip_mreqn
81 +
82 +type sysIPMreqSource C.struct_ip_mreq_source
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_netbsd.go new
+37
@@ -0,0 +1,37 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <netinet/in.h>
13 +*/
14 +import "C"
15 +
16 +const (
17 + sysIP_OPTIONS = C.IP_OPTIONS
18 + sysIP_HDRINCL = C.IP_HDRINCL
19 + sysIP_TOS = C.IP_TOS
20 + sysIP_TTL = C.IP_TTL
21 + sysIP_RECVOPTS = C.IP_RECVOPTS
22 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
23 + sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
24 + sysIP_RETOPTS = C.IP_RETOPTS
25 + sysIP_RECVIF = C.IP_RECVIF
26 + sysIP_RECVTTL = C.IP_RECVTTL
27 +
28 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
29 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
30 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
31 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
32 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
33 +
34 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
35 +)
36 +
37 +type sysIPMreq C.struct_ip_mreq
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_openbsd.go new
+37
@@ -0,0 +1,37 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <netinet/in.h>
13 +*/
14 +import "C"
15 +
16 +const (
17 + sysIP_OPTIONS = C.IP_OPTIONS
18 + sysIP_HDRINCL = C.IP_HDRINCL
19 + sysIP_TOS = C.IP_TOS
20 + sysIP_TTL = C.IP_TTL
21 + sysIP_RECVOPTS = C.IP_RECVOPTS
22 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
23 + sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
24 + sysIP_RETOPTS = C.IP_RETOPTS
25 + sysIP_RECVIF = C.IP_RECVIF
26 + sysIP_RECVTTL = C.IP_RECVTTL
27 +
28 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
29 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
30 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
31 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
32 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
33 +
34 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
35 +)
36 +
37 +type sysIPMreq C.struct_ip_mreq
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/defs_solaris.go new
+57
@@ -0,0 +1,57 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in_addr [4]byte /* in_addr */
8 +
9 +package ipv4
10 +
11 +/*
12 +#include <netinet/in.h>
13 +*/
14 +import "C"
15 +
16 +const (
17 + sysIP_OPTIONS = C.IP_OPTIONS
18 + sysIP_HDRINCL = C.IP_HDRINCL
19 + sysIP_TOS = C.IP_TOS
20 + sysIP_TTL = C.IP_TTL
21 + sysIP_RECVOPTS = C.IP_RECVOPTS
22 + sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
23 + sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
24 + sysIP_RETOPTS = C.IP_RETOPTS
25 + sysIP_RECVIF = C.IP_RECVIF
26 + sysIP_RECVSLLA = C.IP_RECVSLLA
27 + sysIP_RECVTTL = C.IP_RECVTTL
28 + sysIP_NEXTHOP = C.IP_NEXTHOP
29 + sysIP_PKTINFO = C.IP_PKTINFO
30 + sysIP_RECVPKTINFO = C.IP_RECVPKTINFO
31 + sysIP_DONTFRAG = C.IP_DONTFRAG
32 + sysIP_BOUND_IF = C.IP_BOUND_IF
33 + sysIP_UNSPEC_SRC = C.IP_UNSPEC_SRC
34 + sysIP_BROADCAST_TTL = C.IP_BROADCAST_TTL
35 + sysIP_DHCPINIT_IF = C.IP_DHCPINIT_IF
36 +
37 + sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
38 + sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
39 + sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP
40 + sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
41 + sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
42 + sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE
43 + sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE
44 + sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP
45 + sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP
46 +
47 + sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
48 +
49 + sysSizeofIPMreq = C.sizeof_struct_ip_mreq
50 + sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
51 +)
52 +
53 +type sysInetPktinfo C.struct_in_pktinfo
54 +
55 +type sysIPMreq C.struct_ip_mreq
56 +
57 +type sysIPMreqSource C.struct_ip_mreq_source
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/dgramopt_posix.go new
+129
@@ -0,0 +1,129 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd windows
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// MulticastTTL returns the time-to-live field value for outgoing
15 +// multicast packets.
16 +func (c *dgramOpt) MulticastTTL() (int, error) {
17 + if !c.ok() {
18 + return 0, syscall.EINVAL
19 + }
20 + fd, err := c.sysfd()
21 + if err != nil {
22 + return 0, err
23 + }
24 + return getInt(fd, &sockOpts[ssoMulticastTTL])
25 +}
26 +
27 +// SetMulticastTTL sets the time-to-live field value for future
28 +// outgoing multicast packets.
29 +func (c *dgramOpt) SetMulticastTTL(ttl int) error {
30 + if !c.ok() {
31 + return syscall.EINVAL
32 + }
33 + fd, err := c.sysfd()
34 + if err != nil {
35 + return err
36 + }
37 + return setInt(fd, &sockOpts[ssoMulticastTTL], ttl)
38 +}
39 +
40 +// MulticastInterface returns the default interface for multicast
41 +// packet transmissions.
42 +func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
43 + if !c.ok() {
44 + return nil, syscall.EINVAL
45 + }
46 + fd, err := c.sysfd()
47 + if err != nil {
48 + return nil, err
49 + }
50 + return getInterface(fd, &sockOpts[ssoMulticastInterface])
51 +}
52 +
53 +// SetMulticastInterface sets the default interface for future
54 +// multicast packet transmissions.
55 +func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
56 + if !c.ok() {
57 + return syscall.EINVAL
58 + }
59 + fd, err := c.sysfd()
60 + if err != nil {
61 + return err
62 + }
63 + return setInterface(fd, &sockOpts[ssoMulticastInterface], ifi)
64 +}
65 +
66 +// MulticastLoopback reports whether transmitted multicast packets
67 +// should be copied and send back to the originator.
68 +func (c *dgramOpt) MulticastLoopback() (bool, error) {
69 + if !c.ok() {
70 + return false, syscall.EINVAL
71 + }
72 + fd, err := c.sysfd()
73 + if err != nil {
74 + return false, err
75 + }
76 + on, err := getInt(fd, &sockOpts[ssoMulticastLoopback])
77 + if err != nil {
78 + return false, err
79 + }
80 + return on == 1, nil
81 +}
82 +
83 +// SetMulticastLoopback sets whether transmitted multicast packets
84 +// should be copied and send back to the originator.
85 +func (c *dgramOpt) SetMulticastLoopback(on bool) error {
86 + if !c.ok() {
87 + return syscall.EINVAL
88 + }
89 + fd, err := c.sysfd()
90 + if err != nil {
91 + return err
92 + }
93 + return setInt(fd, &sockOpts[ssoMulticastLoopback], boolint(on))
94 +}
95 +
96 +// JoinGroup joins the group address group on the interface ifi.
97 +// It uses the system assigned multicast interface when ifi is nil,
98 +// although this is not recommended because the assignment depends on
99 +// platforms and sometimes it might require routing configuration.
100 +func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
101 + if !c.ok() {
102 + return syscall.EINVAL
103 + }
104 + fd, err := c.sysfd()
105 + if err != nil {
106 + return err
107 + }
108 + grp := netAddrToIP4(group)
109 + if grp == nil {
110 + return errMissingAddress
111 + }
112 + return setGroup(fd, &sockOpts[ssoJoinGroup], ifi, grp)
113 +}
114 +
115 +// LeaveGroup leaves the group address group on the interface ifi.
116 +func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
117 + if !c.ok() {
118 + return syscall.EINVAL
119 + }
120 + fd, err := c.sysfd()
121 + if err != nil {
122 + return err
123 + }
124 + grp := netAddrToIP4(group)
125 + if grp == nil {
126 + return errMissingAddress
127 + }
128 + return setGroup(fd, &sockOpts[ssoLeaveGroup], ifi, grp)
129 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/dgramopt_stub.go new
+49
@@ -0,0 +1,49 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv4
8 +
9 +import "net"
10 +
11 +func (c *dgramOpt) MulticastTTL() (int, error) {
12 + // TODO(mikio): Implement this
13 + return 0, errOpNoSupport
14 +}
15 +
16 +func (c *dgramOpt) SetMulticastTTL(ttl int) error {
17 + // TODO(mikio): Implement this
18 + return errOpNoSupport
19 +}
20 +
21 +func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
22 + // TODO(mikio): Implement this
23 + return nil, errOpNoSupport
24 +}
25 +
26 +func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
27 + // TODO(mikio): Implement this
28 + return errOpNoSupport
29 +}
30 +
31 +func (c *dgramOpt) MulticastLoopback() (bool, error) {
32 + // TODO(mikio): Implement this
33 + return false, errOpNoSupport
34 +}
35 +
36 +func (c *dgramOpt) SetMulticastLoopback(on bool) error {
37 + // TODO(mikio): Implement this
38 + return errOpNoSupport
39 +}
40 +
41 +func (c *dgramOpt) JoinGroup(ifi *net.Interface, grp net.Addr) error {
42 + // TODO(mikio): Implement this
43 + return errOpNoSupport
44 +}
45 +
46 +func (c *dgramOpt) LeaveGroup(ifi *net.Interface, grp net.Addr) error {
47 + // TODO(mikio): Implement this
48 + return errOpNoSupport
49 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/doc.go new
+196
@@ -0,0 +1,196 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// Package ipv4 implements IP-level socket options for the Internet
6 +// Protocol version 4.
7 +//
8 +// The package provides IP-level socket options that allow
9 +// manipulation of IPv4 facilities. The IPv4 and basic host
10 +// requirements for IPv4 are defined in RFC 791, RFC 1112 and RFC
11 +// 1122.
12 +//
13 +//
14 +// Unicasting
15 +//
16 +// The options for unicasting are available for net.TCPConn,
17 +// net.UDPConn and net.IPConn which are created as network connections
18 +// that use the IPv4 transport. When a single TCP connection carrying
19 +// a data flow of multiple packets needs to indicate the flow is
20 +// important, ipv4.Conn is used to set the type-of-service field on
21 +// the IPv4 header for each packet.
22 +//
23 +// ln, err := net.Listen("tcp4", "0.0.0.0:1024")
24 +// if err != nil {
25 +// // error handling
26 +// }
27 +// defer ln.Close()
28 +// for {
29 +// c, err := ln.Accept()
30 +// if err != nil {
31 +// // error handling
32 +// }
33 +// go func(c net.Conn) {
34 +// defer c.Close()
35 +//
36 +// The outgoing packets will be labeled DiffServ assured forwarding
37 +// class 1 low drop precedence, as known as AF11 packets.
38 +//
39 +// if err := ipv4.NewConn(c).SetTOS(DiffServAF11); err != nil {
40 +// // error handling
41 +// }
42 +// if _, err := c.Write(data); err != nil {
43 +// // error handling
44 +// }
45 +// }(c)
46 +// }
47 +//
48 +//
49 +// Multicasting
50 +//
51 +// The options for multicasting are available for net.UDPConn and
52 +// net.IPconn which are created as network connections that use the
53 +// IPv4 transport. A few network facilities must be prepared before
54 +// you begin multicasting, at a minimum joining network interfaces and
55 +// multicast groups.
56 +//
57 +// en0, err := net.InterfaceByName("en0")
58 +// if err != nil {
59 +// // error handling
60 +// }
61 +// en1, err := net.InterfaceByIndex(911)
62 +// if err != nil {
63 +// // error handling
64 +// }
65 +// group := net.IPv4(224, 0, 0, 250)
66 +//
67 +// First, an application listens to an appropriate address with an
68 +// appropriate service port.
69 +//
70 +// c, err := net.ListenPacket("udp4", "0.0.0.0:1024")
71 +// if err != nil {
72 +// // error handling
73 +// }
74 +// defer c.Close()
75 +//
76 +// Second, the application joins multicast groups, starts listening to
77 +// the groups on the specified network interfaces. Note that the
78 +// service port for transport layer protocol does not matter with this
79 +// operation as joining groups affects only network and link layer
80 +// protocols, such as IPv4 and Ethernet.
81 +//
82 +// p := ipv4.NewPacketConn(c)
83 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil {
84 +// // error handling
85 +// }
86 +// if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil {
87 +// // error handling
88 +// }
89 +//
90 +// The application might set per packet control message transmissions
91 +// between the protocol stack within the kernel. When the application
92 +// needs a destination address on an incoming packet,
93 +// SetControlMessage of ipv4.PacketConn is used to enable control
94 +// message transmissons.
95 +//
96 +// if err := p.SetControlMessage(ipv4.FlagDst, true); err != nil {
97 +// // error handling
98 +// }
99 +//
100 +// The application could identify whether the received packets are
101 +// of interest by using the control message that contains the
102 +// destination address of the received packet.
103 +//
104 +// b := make([]byte, 1500)
105 +// for {
106 +// n, cm, src, err := p.ReadFrom(b)
107 +// if err != nil {
108 +// // error handling
109 +// }
110 +// if cm.Dst.IsMulticast() {
111 +// if cm.Dst.Equal(group)
112 +// // joined group, do something
113 +// } else {
114 +// // unknown group, discard
115 +// continue
116 +// }
117 +// }
118 +//
119 +// The application can also send both unicast and multicast packets.
120 +//
121 +// p.SetTOS(DiffServCS0)
122 +// p.SetTTL(16)
123 +// if _, err := p.WriteTo(data, nil, src); err != nil {
124 +// // error handling
125 +// }
126 +// dst := &net.UDPAddr{IP: group, Port: 1024}
127 +// for _, ifi := range []*net.Interface{en0, en1} {
128 +// if err := p.SetMulticastInterface(ifi); err != nil {
129 +// // error handling
130 +// }
131 +// p.SetMulticastTTL(2)
132 +// if _, err := p.WriteTo(data, nil, dst); err != nil {
133 +// // error handling
134 +// }
135 +// }
136 +// }
137 +//
138 +//
139 +// More multicasting
140 +//
141 +// An application that uses PacketConn or RawConn may join multiple
142 +// multicast groups. For example, a UDP listener with port 1024 might
143 +// join two different groups across over two different network
144 +// interfaces by using:
145 +//
146 +// c, err := net.ListenPacket("udp4", "0.0.0.0:1024")
147 +// if err != nil {
148 +// // error handling
149 +// }
150 +// defer c.Close()
151 +// p := ipv4.NewPacketConn(c)
152 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
153 +// // error handling
154 +// }
155 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}); err != nil {
156 +// // error handling
157 +// }
158 +// if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}); err != nil {
159 +// // error handling
160 +// }
161 +//
162 +// It is possible for multiple UDP listeners that listen on the same
163 +// UDP port to join the same multicast group. The net package will
164 +// provide a socket that listens to a wildcard address with reusable
165 +// UDP port when an appropriate multicast address prefix is passed to
166 +// the net.ListenPacket or net.ListenUDP.
167 +//
168 +// c1, err := net.ListenPacket("udp4", "224.0.0.0:1024")
169 +// if err != nil {
170 +// // error handling
171 +// }
172 +// defer c1.Close()
173 +// c2, err := net.ListenPacket("udp4", "224.0.0.0:1024")
174 +// if err != nil {
175 +// // error handling
176 +// }
177 +// defer c2.Close()
178 +// p1 := ipv4.NewPacketConn(c1)
179 +// if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
180 +// // error handling
181 +// }
182 +// p2 := ipv4.NewPacketConn(c2)
183 +// if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
184 +// // error handling
185 +// }
186 +//
187 +// Also it is possible for the application to leave or rejoin a
188 +// multicast group on the network interface.
189 +//
190 +// if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
191 +// // error handling
192 +// }
193 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 250)}); err != nil {
194 +// // error handling
195 +// }
196 +package ipv4
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/endpoint.go new
+181
@@ -0,0 +1,181 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "syscall"
10 + "time"
11 +)
12 +
13 +// A Conn represents a network endpoint that uses the IPv4 transport.
14 +// It is used to control basic IP-level socket options such as TOS and
15 +// TTL.
16 +type Conn struct {
17 + genericOpt
18 +}
19 +
20 +type genericOpt struct {
21 + net.Conn
22 +}
23 +
24 +func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
25 +
26 +// NewConn returns a new Conn.
27 +func NewConn(c net.Conn) *Conn {
28 + return &Conn{
29 + genericOpt: genericOpt{Conn: c},
30 + }
31 +}
32 +
33 +// A PacketConn represents a packet network endpoint that uses the
34 +// IPv4 transport. It is used to control several IP-level socket
35 +// options including multicasting. It also provides datagram based
36 +// network I/O methods specific to the IPv4 and higher layer protocols
37 +// such as UDP.
38 +type PacketConn struct {
39 + genericOpt
40 + dgramOpt
41 + payloadHandler
42 +}
43 +
44 +type dgramOpt struct {
45 + net.PacketConn
46 +}
47 +
48 +func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil }
49 +
50 +// SetControlMessage sets the per packet IP-level socket options.
51 +func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
52 + if !c.payloadHandler.ok() {
53 + return syscall.EINVAL
54 + }
55 + fd, err := c.payloadHandler.sysfd()
56 + if err != nil {
57 + return err
58 + }
59 + return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on)
60 +}
61 +
62 +// SetDeadline sets the read and write deadlines associated with the
63 +// endpoint.
64 +func (c *PacketConn) SetDeadline(t time.Time) error {
65 + if !c.payloadHandler.ok() {
66 + return syscall.EINVAL
67 + }
68 + return c.payloadHandler.PacketConn.SetDeadline(t)
69 +}
70 +
71 +// SetReadDeadline sets the read deadline associated with the
72 +// endpoint.
73 +func (c *PacketConn) SetReadDeadline(t time.Time) error {
74 + if !c.payloadHandler.ok() {
75 + return syscall.EINVAL
76 + }
77 + return c.payloadHandler.PacketConn.SetReadDeadline(t)
78 +}
79 +
80 +// SetWriteDeadline sets the write deadline associated with the
81 +// endpoint.
82 +func (c *PacketConn) SetWriteDeadline(t time.Time) error {
83 + if !c.payloadHandler.ok() {
84 + return syscall.EINVAL
85 + }
86 + return c.payloadHandler.PacketConn.SetWriteDeadline(t)
87 +}
88 +
89 +// Close closes the endpoint.
90 +func (c *PacketConn) Close() error {
91 + if !c.payloadHandler.ok() {
92 + return syscall.EINVAL
93 + }
94 + return c.payloadHandler.PacketConn.Close()
95 +}
96 +
97 +// NewPacketConn returns a new PacketConn using c as its underlying
98 +// transport.
99 +func NewPacketConn(c net.PacketConn) *PacketConn {
100 + return &PacketConn{
101 + genericOpt: genericOpt{Conn: c.(net.Conn)},
102 + dgramOpt: dgramOpt{PacketConn: c},
103 + payloadHandler: payloadHandler{PacketConn: c},
104 + }
105 +}
106 +
107 +// A RawConn represents a packet network endpoint that uses the IPv4
108 +// transport. It is used to control several IP-level socket options
109 +// including IPv4 header manipulation. It also provides datagram
110 +// based network I/O methods specific to the IPv4 and higher layer
111 +// protocols that handle IPv4 datagram directly such as OSPF, GRE.
112 +type RawConn struct {
113 + genericOpt
114 + dgramOpt
115 + packetHandler
116 +}
117 +
118 +// SetControlMessage sets the per packet IP-level socket options.
119 +func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
120 + if !c.packetHandler.ok() {
121 + return syscall.EINVAL
122 + }
123 + fd, err := c.packetHandler.sysfd()
124 + if err != nil {
125 + return err
126 + }
127 + return setControlMessage(fd, &c.packetHandler.rawOpt, cf, on)
128 +}
129 +
130 +// SetDeadline sets the read and write deadlines associated with the
131 +// endpoint.
132 +func (c *RawConn) SetDeadline(t time.Time) error {
133 + if !c.packetHandler.ok() {
134 + return syscall.EINVAL
135 + }
136 + return c.packetHandler.c.SetDeadline(t)
137 +}
138 +
139 +// SetReadDeadline sets the read deadline associated with the
140 +// endpoint.
141 +func (c *RawConn) SetReadDeadline(t time.Time) error {
142 + if !c.packetHandler.ok() {
143 + return syscall.EINVAL
144 + }
145 + return c.packetHandler.c.SetReadDeadline(t)
146 +}
147 +
148 +// SetWriteDeadline sets the write deadline associated with the
149 +// endpoint.
150 +func (c *RawConn) SetWriteDeadline(t time.Time) error {
151 + if !c.packetHandler.ok() {
152 + return syscall.EINVAL
153 + }
154 + return c.packetHandler.c.SetWriteDeadline(t)
155 +}
156 +
157 +// Close closes the endpoint.
158 +func (c *RawConn) Close() error {
159 + if !c.packetHandler.ok() {
160 + return syscall.EINVAL
161 + }
162 + return c.packetHandler.c.Close()
163 +}
164 +
165 +// NewRawConn returns a new RawConn using c as its underlying
166 +// transport.
167 +func NewRawConn(c net.PacketConn) (*RawConn, error) {
168 + r := &RawConn{
169 + genericOpt: genericOpt{Conn: c.(net.Conn)},
170 + dgramOpt: dgramOpt{PacketConn: c},
171 + packetHandler: packetHandler{c: c.(*net.IPConn)},
172 + }
173 + fd, err := r.packetHandler.sysfd()
174 + if err != nil {
175 + return nil, err
176 + }
177 + if err := setInt(fd, &sockOpts[ssoHeaderPrepend], boolint(true)); err != nil {
178 + return nil, err
179 + }
180 + return r, nil
181 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/error_posix_test.go new
+31
@@ -0,0 +1,31 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
6 +
7 +package ipv4_test
8 +
9 +import (
10 + "os"
11 + "syscall"
12 +)
13 +
14 +func protocolNotSupported(err error) bool {
15 + switch err := err.(type) {
16 + case syscall.Errno:
17 + switch err {
18 + case syscall.EPROTONOSUPPORT, syscall.ENOPROTOOPT:
19 + return true
20 + }
21 + case *os.SyscallError:
22 + switch err := err.Err.(type) {
23 + case syscall.Errno:
24 + switch err {
25 + case syscall.EPROTONOSUPPORT, syscall.ENOPROTOOPT:
26 + return true
27 + }
28 + }
29 + }
30 + return false
31 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/error_stub_test.go new
+11
@@ -0,0 +1,11 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9
6 +
7 +package ipv4_test
8 +
9 +func protocolNotSupported(err error) bool {
10 + return false
11 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/example_test.go new
+285
@@ -0,0 +1,285 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "log"
9 + "net"
10 +
11 + "code.google.com/p/go.net/ipv4"
12 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
13 +)
14 +
15 +func ExampleUnicastTCPListener() {
16 + ln, err := net.Listen("tcp4", "0.0.0.0:1024")
17 + if err != nil {
18 + log.Fatal(err)
19 + }
20 + defer ln.Close()
21 + for {
22 + c, err := ln.Accept()
23 + if err != nil {
24 + log.Fatal(err)
25 + }
26 + go func(c net.Conn) {
27 + defer c.Close()
28 + err := ipv4.NewConn(c).SetTOS(iana.DiffServAF11)
29 + if err != nil {
30 + log.Fatal(err)
31 + }
32 + _, err = c.Write([]byte("HELLO-R-U-THERE-ACK"))
33 + if err != nil {
34 + log.Fatal(err)
35 + }
36 + }(c)
37 + }
38 +}
39 +
40 +func ExampleMulticastUDPListener() {
41 + en0, err := net.InterfaceByName("en0")
42 + if err != nil {
43 + log.Fatal(err)
44 + }
45 + en1, err := net.InterfaceByIndex(911)
46 + if err != nil {
47 + log.Fatal(err)
48 + }
49 + group := net.IPv4(224, 0, 0, 250)
50 +
51 + c, err := net.ListenPacket("udp4", "0.0.0.0:1024")
52 + if err != nil {
53 + log.Fatal(err)
54 + }
55 + defer c.Close()
56 +
57 + p := ipv4.NewPacketConn(c)
58 + err = p.JoinGroup(en0, &net.UDPAddr{IP: group})
59 + if err != nil {
60 + log.Fatal(err)
61 + }
62 + err = p.JoinGroup(en1, &net.UDPAddr{IP: group})
63 + if err != nil {
64 + log.Fatal(err)
65 + }
66 +
67 + err = p.SetControlMessage(ipv4.FlagDst, true)
68 + if err != nil {
69 + log.Fatal(err)
70 + }
71 +
72 + b := make([]byte, 1500)
73 + for {
74 + n, cm, src, err := p.ReadFrom(b)
75 + if err != nil {
76 + log.Fatal(err)
77 + }
78 + if cm.Dst.IsMulticast() {
79 + if cm.Dst.Equal(group) {
80 + // joined group, do something
81 + } else {
82 + // unknown group, discard
83 + continue
84 + }
85 + }
86 + p.SetTOS(iana.DiffServCS7)
87 + p.SetTTL(16)
88 + _, err = p.WriteTo(b[:n], nil, src)
89 + if err != nil {
90 + log.Fatal(err)
91 + }
92 + dst := &net.UDPAddr{IP: group, Port: 1024}
93 + for _, ifi := range []*net.Interface{en0, en1} {
94 + err := p.SetMulticastInterface(ifi)
95 + if err != nil {
96 + log.Fatal(err)
97 + }
98 + p.SetMulticastTTL(2)
99 + _, err = p.WriteTo(b[:n], nil, dst)
100 + if err != nil {
101 + log.Fatal(err)
102 + }
103 + }
104 + }
105 +
106 + err = p.LeaveGroup(en1, &net.UDPAddr{IP: group})
107 + if err != nil {
108 + log.Fatal(err)
109 + }
110 + newgroup := net.IPv4(224, 0, 0, 249)
111 + err = p.JoinGroup(en1, &net.UDPAddr{IP: newgroup})
112 + if err != nil {
113 + log.Fatal(err)
114 + }
115 +}
116 +
117 +type OSPFHeader struct {
118 + Version byte
119 + Type byte
120 + Len uint16
121 + RouterID uint32
122 + AreaID uint32
123 + Checksum uint16
124 +}
125 +
126 +const (
127 + OSPFHeaderLen = 14
128 + OSPFHelloHeaderLen = 20
129 + OSPF_VERSION = 2
130 + OSPF_TYPE_HELLO = iota + 1
131 + OSPF_TYPE_DB_DESCRIPTION
132 + OSPF_TYPE_LS_REQUEST
133 + OSPF_TYPE_LS_UPDATE
134 + OSPF_TYPE_LS_ACK
135 +)
136 +
137 +var (
138 + AllSPFRouters = net.IPv4(224, 0, 0, 5)
139 + AllDRouters = net.IPv4(224, 0, 0, 6)
140 +)
141 +
142 +func ExampleIPOSPFListener() {
143 + var ifs []*net.Interface
144 + en0, err := net.InterfaceByName("en0")
145 + if err != nil {
146 + log.Fatal(err)
147 + }
148 + ifs = append(ifs, en0)
149 + en1, err := net.InterfaceByIndex(911)
150 + if err != nil {
151 + log.Fatal(err)
152 + }
153 + ifs = append(ifs, en1)
154 +
155 + c, err := net.ListenPacket("ip4:89", "0.0.0.0") // OSFP for IPv4
156 + if err != nil {
157 + log.Fatal(err)
158 + }
159 + defer c.Close()
160 +
161 + r, err := ipv4.NewRawConn(c)
162 + if err != nil {
163 + log.Fatal(err)
164 + }
165 + for _, ifi := range ifs {
166 + err := r.JoinGroup(ifi, &net.IPAddr{IP: AllSPFRouters})
167 + if err != nil {
168 + log.Fatal(err)
169 + }
170 + err = r.JoinGroup(ifi, &net.IPAddr{IP: AllDRouters})
171 + if err != nil {
172 + log.Fatal(err)
173 + }
174 + }
175 +
176 + err = r.SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true)
177 + if err != nil {
178 + log.Fatal(err)
179 + }
180 + r.SetTOS(iana.DiffServCS6)
181 +
182 + parseOSPFHeader := func(b []byte) *OSPFHeader {
183 + if len(b) < OSPFHeaderLen {
184 + return nil
185 + }
186 + return &OSPFHeader{
187 + Version: b[0],
188 + Type: b[1],
189 + Len: uint16(b[2])<<8 | uint16(b[3]),
190 + RouterID: uint32(b[4])<<24 | uint32(b[5])<<16 | uint32(b[6])<<8 | uint32(b[7]),
191 + AreaID: uint32(b[8])<<24 | uint32(b[9])<<16 | uint32(b[10])<<8 | uint32(b[11]),
192 + Checksum: uint16(b[12])<<8 | uint16(b[13]),
193 + }
194 + }
195 +
196 + b := make([]byte, 1500)
197 + for {
198 + iph, p, _, err := r.ReadFrom(b)
199 + if err != nil {
200 + log.Fatal(err)
201 + }
202 + if iph.Version != ipv4.Version {
203 + continue
204 + }
205 + if iph.Dst.IsMulticast() {
206 + if !iph.Dst.Equal(AllSPFRouters) && !iph.Dst.Equal(AllDRouters) {
207 + continue
208 + }
209 + }
210 + ospfh := parseOSPFHeader(p)
211 + if ospfh == nil {
212 + continue
213 + }
214 + if ospfh.Version != OSPF_VERSION {
215 + continue
216 + }
217 + switch ospfh.Type {
218 + case OSPF_TYPE_HELLO:
219 + case OSPF_TYPE_DB_DESCRIPTION:
220 + case OSPF_TYPE_LS_REQUEST:
221 + case OSPF_TYPE_LS_UPDATE:
222 + case OSPF_TYPE_LS_ACK:
223 + }
224 + }
225 +}
226 +
227 +func ExampleWriteIPOSPFHello() {
228 + var ifs []*net.Interface
229 + en0, err := net.InterfaceByName("en0")
230 + if err != nil {
231 + log.Fatal(err)
232 + }
233 + ifs = append(ifs, en0)
234 + en1, err := net.InterfaceByIndex(911)
235 + if err != nil {
236 + log.Fatal(err)
237 + }
238 + ifs = append(ifs, en1)
239 +
240 + c, err := net.ListenPacket("ip4:89", "0.0.0.0") // OSPF for IPv4
241 + if err != nil {
242 + log.Fatal(err)
243 + }
244 + defer c.Close()
245 +
246 + r, err := ipv4.NewRawConn(c)
247 + if err != nil {
248 + log.Fatal(err)
249 + }
250 + for _, ifi := range ifs {
251 + err := r.JoinGroup(ifi, &net.IPAddr{IP: AllSPFRouters})
252 + if err != nil {
253 + log.Fatal(err)
254 + }
255 + err = r.JoinGroup(ifi, &net.IPAddr{IP: AllDRouters})
256 + if err != nil {
257 + log.Fatal(err)
258 + }
259 + }
260 +
261 + hello := make([]byte, OSPFHelloHeaderLen)
262 + ospf := make([]byte, OSPFHeaderLen)
263 + ospf[0] = OSPF_VERSION
264 + ospf[1] = OSPF_TYPE_HELLO
265 + ospf = append(ospf, hello...)
266 + iph := &ipv4.Header{}
267 + iph.Version = ipv4.Version
268 + iph.Len = ipv4.HeaderLen
269 + iph.TOS = iana.DiffServCS6
270 + iph.TotalLen = ipv4.HeaderLen + len(ospf)
271 + iph.TTL = 1
272 + iph.Protocol = 89
273 + iph.Dst = AllSPFRouters
274 +
275 + for _, ifi := range ifs {
276 + err := r.SetMulticastInterface(ifi)
277 + if err != nil {
278 + return
279 + }
280 + err = r.WriteTo(iph, ospf, nil)
281 + if err != nil {
282 + return
283 + }
284 + }
285 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/gen.go new
+201
@@ -0,0 +1,201 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +//go:generate go run gen.go
8 +
9 +// This program generates system adaptation constants and types,
10 +// internet protocol constants and tables by reading template files
11 +// and IANA protocol registries.
12 +package main
13 +
14 +import (
15 + "bytes"
16 + "encoding/xml"
17 + "fmt"
18 + "go/format"
19 + "io"
20 + "io/ioutil"
21 + "net/http"
22 + "os"
23 + "os/exec"
24 + "runtime"
25 + "strconv"
26 + "strings"
27 +)
28 +
29 +func main() {
30 + if err := genzsys(); err != nil {
31 + fmt.Fprintln(os.Stderr, err)
32 + os.Exit(1)
33 + }
34 + if err := geniana(); err != nil {
35 + fmt.Fprintln(os.Stderr, err)
36 + os.Exit(1)
37 + }
38 +}
39 +
40 +func genzsys() error {
41 + defs := "defs_" + runtime.GOOS + ".go"
42 + f, err := os.Open(defs)
43 + if err != nil {
44 + if os.IsNotExist(err) {
45 + return nil
46 + }
47 + return err
48 + }
49 + f.Close()
50 + cmd := exec.Command("go", "tool", "cgo", "-godefs", defs)
51 + b, err := cmd.Output()
52 + if err != nil {
53 + return err
54 + }
55 + switch runtime.GOOS {
56 + case "dragonfly", "solaris":
57 + // The ipv4 pacakge still supports go1.2, and so we
58 + // need to take care of additional platforms in go1.3
59 + // and above for working with go1.2.
60 + b = bytes.Replace(b, []byte("package ipv4\n"), []byte("// +build "+runtime.GOOS+"\n\npackage ipv4\n"), 1)
61 + }
62 + b, err = format.Source(b)
63 + if err != nil {
64 + return err
65 + }
66 + if err := ioutil.WriteFile("zsys_"+runtime.GOOS+".go", b, 0644); err != nil {
67 + return err
68 + }
69 + return nil
70 +}
71 +
72 +var registries = []struct {
73 + url string
74 + parse func(io.Writer, io.Reader) error
75 +}{
76 + {
77 + "http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
78 + parseICMPv4Parameters,
79 + },
80 +}
81 +
82 +func geniana() error {
83 + var bb bytes.Buffer
84 + fmt.Fprintf(&bb, "// go generate gen.go\n")
85 + fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
86 + fmt.Fprintf(&bb, "package ipv4\n\n")
87 + for _, r := range registries {
88 + resp, err := http.Get(r.url)
89 + if err != nil {
90 + return err
91 + }
92 + defer resp.Body.Close()
93 + if resp.StatusCode != http.StatusOK {
94 + return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url)
95 + }
96 + if err := r.parse(&bb, resp.Body); err != nil {
97 + return err
98 + }
99 + fmt.Fprintf(&bb, "\n")
100 + }
101 + b, err := format.Source(bb.Bytes())
102 + if err != nil {
103 + return err
104 + }
105 + if err := ioutil.WriteFile("iana.go", b, 0644); err != nil {
106 + return err
107 + }
108 + return nil
109 +}
110 +
111 +func parseICMPv4Parameters(w io.Writer, r io.Reader) error {
112 + dec := xml.NewDecoder(r)
113 + var icp icmpv4Parameters
114 + if err := dec.Decode(&icp); err != nil {
115 + return err
116 + }
117 + prs := icp.escape()
118 + fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
119 + fmt.Fprintf(w, "const (\n")
120 + for _, pr := range prs {
121 + if pr.Descr == "" {
122 + continue
123 + }
124 + fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value)
125 + fmt.Fprintf(w, "// %s\n", pr.OrigDescr)
126 + }
127 + fmt.Fprintf(w, ")\n\n")
128 + fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
129 + fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n")
130 + for _, pr := range prs {
131 + if pr.Descr == "" {
132 + continue
133 + }
134 + fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr))
135 + }
136 + fmt.Fprintf(w, "}\n")
137 + return nil
138 +}
139 +
140 +type icmpv4Parameters struct {
141 + XMLName xml.Name `xml:"registry"`
142 + Title string `xml:"title"`
143 + Updated string `xml:"updated"`
144 + Registries []struct {
145 + Title string `xml:"title"`
146 + Records []struct {
147 + Value string `xml:"value"`
148 + Descr string `xml:"description"`
149 + } `xml:"record"`
150 + } `xml:"registry"`
151 +}
152 +
153 +type canonICMPv4ParamRecord struct {
154 + OrigDescr string
155 + Descr string
156 + Value int
157 +}
158 +
159 +func (icp *icmpv4Parameters) escape() []canonICMPv4ParamRecord {
160 + id := -1
161 + for i, r := range icp.Registries {
162 + if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") {
163 + id = i
164 + break
165 + }
166 + }
167 + if id < 0 {
168 + return nil
169 + }
170 + prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records))
171 + sr := strings.NewReplacer(
172 + "Messages", "",
173 + "Message", "",
174 + "ICMP", "",
175 + "+", "P",
176 + "-", "",
177 + "/", "",
178 + ".", "",
179 + " ", "",
180 + )
181 + for i, pr := range icp.Registries[id].Records {
182 + if strings.Contains(pr.Descr, "Reserved") ||
183 + strings.Contains(pr.Descr, "Unassigned") ||
184 + strings.Contains(pr.Descr, "Deprecated") ||
185 + strings.Contains(pr.Descr, "Experiment") ||
186 + strings.Contains(pr.Descr, "experiment") {
187 + continue
188 + }
189 + ss := strings.Split(pr.Descr, "\n")
190 + if len(ss) > 1 {
191 + prs[i].Descr = strings.Join(ss, " ")
192 + } else {
193 + prs[i].Descr = ss[0]
194 + }
195 + s := strings.TrimSpace(prs[i].Descr)
196 + prs[i].OrigDescr = s
197 + prs[i].Descr = sr.Replace(s)
198 + prs[i].Value, _ = strconv.Atoi(pr.Value)
199 + }
200 + return prs
201 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/genericopt_posix.go new
+59
@@ -0,0 +1,59 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd windows
6 +
7 +package ipv4
8 +
9 +import "syscall"
10 +
11 +// TOS returns the type-of-service field value for outgoing packets.
12 +func (c *genericOpt) TOS() (int, error) {
13 + if !c.ok() {
14 + return 0, syscall.EINVAL
15 + }
16 + fd, err := c.sysfd()
17 + if err != nil {
18 + return 0, err
19 + }
20 + return getInt(fd, &sockOpts[ssoTOS])
21 +}
22 +
23 +// SetTOS sets the type-of-service field value for future outgoing
24 +// packets.
25 +func (c *genericOpt) SetTOS(tos int) error {
26 + if !c.ok() {
27 + return syscall.EINVAL
28 + }
29 + fd, err := c.sysfd()
30 + if err != nil {
31 + return err
32 + }
33 + return setInt(fd, &sockOpts[ssoTOS], tos)
34 +}
35 +
36 +// TTL returns the time-to-live field value for outgoing packets.
37 +func (c *genericOpt) TTL() (int, error) {
38 + if !c.ok() {
39 + return 0, syscall.EINVAL
40 + }
41 + fd, err := c.sysfd()
42 + if err != nil {
43 + return 0, err
44 + }
45 + return getInt(fd, &sockOpts[ssoTTL])
46 +}
47 +
48 +// SetTTL sets the time-to-live field value for future outgoing
49 +// packets.
50 +func (c *genericOpt) SetTTL(ttl int) error {
51 + if !c.ok() {
52 + return syscall.EINVAL
53 + }
54 + fd, err := c.sysfd()
55 + if err != nil {
56 + return err
57 + }
58 + return setInt(fd, &sockOpts[ssoTTL], ttl)
59 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/genericopt_stub.go new
+27
@@ -0,0 +1,27 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv4
8 +
9 +func (c *genericOpt) TOS() (int, error) {
10 + // TODO(mikio): Implement this
11 + return 0, errOpNoSupport
12 +}
13 +
14 +func (c *genericOpt) SetTOS(tos int) error {
15 + // TODO(mikio): Implement this
16 + return errOpNoSupport
17 +}
18 +
19 +func (c *genericOpt) TTL() (int, error) {
20 + // TODO(mikio): Implement this
21 + return 0, errOpNoSupport
22 +}
23 +
24 +func (c *genericOpt) SetTTL(ttl int) error {
25 + // TODO(mikio): Implement this
26 + return errOpNoSupport
27 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/header.go new
+163
@@ -0,0 +1,163 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "errors"
9 + "fmt"
10 + "net"
11 + "runtime"
12 + "syscall"
13 + "unsafe"
14 +)
15 +
16 +var (
17 + errMissingAddress = errors.New("missing address")
18 + errMissingHeader = errors.New("missing header")
19 + errHeaderTooShort = errors.New("header too short")
20 + errBufferTooShort = errors.New("buffer too short")
21 + errInvalidConnType = errors.New("invalid conn type")
22 +)
23 +
24 +// References:
25 +//
26 +// RFC 791 Internet Protocol
27 +// http://tools.ietf.org/html/rfc791
28 +// RFC 1112 Host Extensions for IP Multicasting
29 +// http://tools.ietf.org/html/rfc1112
30 +// RFC 1122 Requirements for Internet Hosts
31 +// http://tools.ietf.org/html/rfc1122
32 +
33 +const (
34 + Version = 4 // protocol version
35 + HeaderLen = 20 // header length without extension headers
36 + maxHeaderLen = 60 // sensible default, revisit if later RFCs define new usage of version and header length fields
37 +)
38 +
39 +const (
40 + posTOS = 1 // type-of-service
41 + posTotalLen = 2 // packet total length
42 + posID = 4 // identification
43 + posFragOff = 6 // fragment offset
44 + posTTL = 8 // time-to-live
45 + posProtocol = 9 // next protocol
46 + posChecksum = 10 // checksum
47 + posSrc = 12 // source address
48 + posDst = 16 // destination address
49 +)
50 +
51 +type HeaderFlags int
52 +
53 +const (
54 + MoreFragments HeaderFlags = 1 << iota // more fragments flag
55 + DontFragment // don't fragment flag
56 +)
57 +
58 +// A Header represents an IPv4 header.
59 +type Header struct {
60 + Version int // protocol version
61 + Len int // header length
62 + TOS int // type-of-service
63 + TotalLen int // packet total length
64 + ID int // identification
65 + Flags HeaderFlags // flags
66 + FragOff int // fragment offset
67 + TTL int // time-to-live
68 + Protocol int // next protocol
69 + Checksum int // checksum
70 + Src net.IP // source address
71 + Dst net.IP // destination address
72 + Options []byte // options, extension headers
73 +}
74 +
75 +func (h *Header) String() string {
76 + if h == nil {
77 + return "<nil>"
78 + }
79 + return fmt.Sprintf("ver: %v, hdrlen: %v, tos: %#x, totallen: %v, id: %#x, flags: %#x, fragoff: %#x, ttl: %v, proto: %v, cksum: %#x, src: %v, dst: %v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.Flags, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst)
80 +}
81 +
82 +// Please refer to the online manual; IP(4) on Darwin, FreeBSD and
83 +// OpenBSD. IP(7) on Linux.
84 +const supportsNewIPInput = runtime.GOOS == "linux" || runtime.GOOS == "openbsd"
85 +
86 +// Marshal returns the binary encoding of the IPv4 header h.
87 +func (h *Header) Marshal() ([]byte, error) {
88 + if h == nil {
89 + return nil, syscall.EINVAL
90 + }
91 + if h.Len < HeaderLen {
92 + return nil, errHeaderTooShort
93 + }
94 + hdrlen := HeaderLen + len(h.Options)
95 + b := make([]byte, hdrlen)
96 + b[0] = byte(Version<<4 | (hdrlen >> 2 & 0x0f))
97 + b[posTOS] = byte(h.TOS)
98 + flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13)
99 + if supportsNewIPInput {
100 + b[posTotalLen], b[posTotalLen+1] = byte(h.TotalLen>>8), byte(h.TotalLen)
101 + b[posFragOff], b[posFragOff+1] = byte(flagsAndFragOff>>8), byte(flagsAndFragOff)
102 + } else {
103 + *(*uint16)(unsafe.Pointer(&b[posTotalLen : posTotalLen+1][0])) = uint16(h.TotalLen)
104 + *(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0])) = uint16(flagsAndFragOff)
105 + }
106 + b[posID], b[posID+1] = byte(h.ID>>8), byte(h.ID)
107 + b[posTTL] = byte(h.TTL)
108 + b[posProtocol] = byte(h.Protocol)
109 + b[posChecksum], b[posChecksum+1] = byte(h.Checksum>>8), byte(h.Checksum)
110 + if ip := h.Src.To4(); ip != nil {
111 + copy(b[posSrc:posSrc+net.IPv4len], ip[:net.IPv4len])
112 + }
113 + if ip := h.Dst.To4(); ip != nil {
114 + copy(b[posDst:posDst+net.IPv4len], ip[:net.IPv4len])
115 + } else {
116 + return nil, errMissingAddress
117 + }
118 + if len(h.Options) > 0 {
119 + copy(b[HeaderLen:], h.Options)
120 + }
121 + return b, nil
122 +}
123 +
124 +// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
125 +var freebsdVersion uint32
126 +
127 +// ParseHeader parses b as an IPv4 header.
128 +func ParseHeader(b []byte) (*Header, error) {
129 + if len(b) < HeaderLen {
130 + return nil, errHeaderTooShort
131 + }
132 + hdrlen := int(b[0]&0x0f) << 2
133 + if hdrlen > len(b) {
134 + return nil, errBufferTooShort
135 + }
136 + h := &Header{}
137 + h.Version = int(b[0] >> 4)
138 + h.Len = hdrlen
139 + h.TOS = int(b[posTOS])
140 + if supportsNewIPInput {
141 + h.TotalLen = int(b[posTotalLen])<<8 | int(b[posTotalLen+1])
142 + h.FragOff = int(b[posFragOff])<<8 | int(b[posFragOff+1])
143 + } else {
144 + h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[posTotalLen : posTotalLen+1][0])))
145 + if runtime.GOOS != "freebsd" || freebsdVersion < 1000000 {
146 + h.TotalLen += hdrlen
147 + }
148 + h.FragOff = int(*(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0])))
149 + }
150 + h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13
151 + h.FragOff = h.FragOff & 0x1fff
152 + h.ID = int(b[posID])<<8 | int(b[posID+1])
153 + h.TTL = int(b[posTTL])
154 + h.Protocol = int(b[posProtocol])
155 + h.Checksum = int(b[posChecksum])<<8 | int(b[posChecksum+1])
156 + h.Src = net.IPv4(b[posSrc], b[posSrc+1], b[posSrc+2], b[posSrc+3])
157 + h.Dst = net.IPv4(b[posDst], b[posDst+1], b[posDst+2], b[posDst+3])
158 + if hdrlen-HeaderLen > 0 {
159 + h.Options = make([]byte, hdrlen-HeaderLen)
160 + copy(h.Options, b[HeaderLen:])
161 + }
162 + return h, nil
163 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/header_test.go new
+104
@@ -0,0 +1,104 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "bytes"
9 + "net"
10 + "reflect"
11 + "runtime"
12 + "testing"
13 +)
14 +
15 +var (
16 + wireHeaderFromKernel = [HeaderLen]byte{
17 + 0x45, 0x01, 0xbe, 0xef,
18 + 0xca, 0xfe, 0x45, 0xdc,
19 + 0xff, 0x01, 0xde, 0xad,
20 + 172, 16, 254, 254,
21 + 192, 168, 0, 1,
22 + }
23 + wireHeaderToKernel = [HeaderLen]byte{
24 + 0x45, 0x01, 0xbe, 0xef,
25 + 0xca, 0xfe, 0x45, 0xdc,
26 + 0xff, 0x01, 0xde, 0xad,
27 + 172, 16, 254, 254,
28 + 192, 168, 0, 1,
29 + }
30 + wireHeaderFromTradBSDKernel = [HeaderLen]byte{
31 + 0x45, 0x01, 0xdb, 0xbe,
32 + 0xca, 0xfe, 0xdc, 0x45,
33 + 0xff, 0x01, 0xde, 0xad,
34 + 172, 16, 254, 254,
35 + 192, 168, 0, 1,
36 + }
37 + wireHeaderFromFreeBSD10Kernel = [HeaderLen]byte{
38 + 0x45, 0x01, 0xef, 0xbe,
39 + 0xca, 0xfe, 0xdc, 0x45,
40 + 0xff, 0x01, 0xde, 0xad,
41 + 172, 16, 254, 254,
42 + 192, 168, 0, 1,
43 + }
44 + wireHeaderToTradBSDKernel = [HeaderLen]byte{
45 + 0x45, 0x01, 0xef, 0xbe,
46 + 0xca, 0xfe, 0xdc, 0x45,
47 + 0xff, 0x01, 0xde, 0xad,
48 + 172, 16, 254, 254,
49 + 192, 168, 0, 1,
50 + }
51 + // TODO(mikio): Add platform dependent wire header formats when
52 + // we support new platforms.
53 +
54 + testHeader = &Header{
55 + Version: Version,
56 + Len: HeaderLen,
57 + TOS: 1,
58 + TotalLen: 0xbeef,
59 + ID: 0xcafe,
60 + Flags: DontFragment,
61 + FragOff: 1500,
62 + TTL: 255,
63 + Protocol: 1,
64 + Checksum: 0xdead,
65 + Src: net.IPv4(172, 16, 254, 254),
66 + Dst: net.IPv4(192, 168, 0, 1),
67 + }
68 +)
69 +
70 +func TestMarshalHeader(t *testing.T) {
71 + b, err := testHeader.Marshal()
72 + if err != nil {
73 + t.Fatalf("ipv4.Header.Marshal failed: %v", err)
74 + }
75 + var wh []byte
76 + if supportsNewIPInput {
77 + wh = wireHeaderToKernel[:]
78 + } else {
79 + wh = wireHeaderToTradBSDKernel[:]
80 + }
81 + if !bytes.Equal(b, wh) {
82 + t.Fatalf("ipv4.Header.Marshal failed: %#v not equal %#v", b, wh)
83 + }
84 +}
85 +
86 +func TestParseHeader(t *testing.T) {
87 + var wh []byte
88 + if supportsNewIPInput {
89 + wh = wireHeaderFromKernel[:]
90 + } else {
91 + if runtime.GOOS == "freebsd" && freebsdVersion >= 1000000 {
92 + wh = wireHeaderFromFreeBSD10Kernel[:]
93 + } else {
94 + wh = wireHeaderFromTradBSDKernel[:]
95 + }
96 + }
97 + h, err := ParseHeader(wh)
98 + if err != nil {
99 + t.Fatalf("ipv4.ParseHeader failed: %v", err)
100 + }
101 + if !reflect.DeepEqual(h, testHeader) {
102 + t.Fatalf("ipv4.ParseHeader failed: %#v not equal %#v", h, testHeader)
103 + }
104 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/helper.go new
+37
@@ -0,0 +1,37 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "errors"
9 + "net"
10 +)
11 +
12 +var (
13 + errOpNoSupport = errors.New("operation not supported")
14 + errNoSuchInterface = errors.New("no such interface")
15 + errNoSuchMulticastInterface = errors.New("no such multicast interface")
16 +)
17 +
18 +func boolint(b bool) int {
19 + if b {
20 + return 1
21 + }
22 + return 0
23 +}
24 +
25 +func netAddrToIP4(a net.Addr) net.IP {
26 + switch v := a.(type) {
27 + case *net.UDPAddr:
28 + if ip := v.IP.To4(); ip != nil {
29 + return ip
30 + }
31 + case *net.IPAddr:
32 + if ip := v.IP.To4(); ip != nil {
33 + return ip
34 + }
35 + }
36 + return nil
37 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/helper_stub.go new
+27
@@ -0,0 +1,27 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv4
8 +
9 +func (c *genericOpt) sysfd() (int, error) {
10 + // TODO(mikio): Implement this
11 + return 0, errOpNoSupport
12 +}
13 +
14 +func (c *dgramOpt) sysfd() (int, error) {
15 + // TODO(mikio): Implement this
16 + return 0, errOpNoSupport
17 +}
18 +
19 +func (c *payloadHandler) sysfd() (int, error) {
20 + // TODO(mikio): Implement this
21 + return 0, errOpNoSupport
22 +}
23 +
24 +func (c *packetHandler) sysfd() (int, error) {
25 + // TODO(mikio): Implement this
26 + return 0, errOpNoSupport
27 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/helper_unix.go new
+50
@@ -0,0 +1,50 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "reflect"
12 +)
13 +
14 +func (c *genericOpt) sysfd() (int, error) {
15 + switch p := c.Conn.(type) {
16 + case *net.TCPConn, *net.UDPConn, *net.IPConn:
17 + return sysfd(p)
18 + }
19 + return 0, errInvalidConnType
20 +}
21 +
22 +func (c *dgramOpt) sysfd() (int, error) {
23 + switch p := c.PacketConn.(type) {
24 + case *net.UDPConn, *net.IPConn:
25 + return sysfd(p.(net.Conn))
26 + }
27 + return 0, errInvalidConnType
28 +}
29 +
30 +func (c *payloadHandler) sysfd() (int, error) {
31 + return sysfd(c.PacketConn.(net.Conn))
32 +}
33 +
34 +func (c *packetHandler) sysfd() (int, error) {
35 + return sysfd(c.c)
36 +}
37 +
38 +func sysfd(c net.Conn) (int, error) {
39 + cv := reflect.ValueOf(c)
40 + switch ce := cv.Elem(); ce.Kind() {
41 + case reflect.Struct:
42 + netfd := ce.FieldByName("conn").FieldByName("fd")
43 + switch fe := netfd.Elem(); fe.Kind() {
44 + case reflect.Struct:
45 + fd := fe.FieldByName("sysfd")
46 + return int(fd.Int()), nil
47 + }
48 + }
49 + return 0, errInvalidConnType
50 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/helper_windows.go new
+49
@@ -0,0 +1,49 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "reflect"
10 + "syscall"
11 +)
12 +
13 +func (c *genericOpt) sysfd() (syscall.Handle, error) {
14 + switch p := c.Conn.(type) {
15 + case *net.TCPConn, *net.UDPConn, *net.IPConn:
16 + return sysfd(p)
17 + }
18 + return syscall.InvalidHandle, errInvalidConnType
19 +}
20 +
21 +func (c *dgramOpt) sysfd() (syscall.Handle, error) {
22 + switch p := c.PacketConn.(type) {
23 + case *net.UDPConn, *net.IPConn:
24 + return sysfd(p.(net.Conn))
25 + }
26 + return syscall.InvalidHandle, errInvalidConnType
27 +}
28 +
29 +func (c *payloadHandler) sysfd() (syscall.Handle, error) {
30 + return sysfd(c.PacketConn.(net.Conn))
31 +}
32 +
33 +func (c *packetHandler) sysfd() (syscall.Handle, error) {
34 + return sysfd(c.c)
35 +}
36 +
37 +func sysfd(c net.Conn) (syscall.Handle, error) {
38 + cv := reflect.ValueOf(c)
39 + switch ce := cv.Elem(); ce.Kind() {
40 + case reflect.Struct:
41 + netfd := ce.FieldByName("conn").FieldByName("fd")
42 + switch fe := netfd.Elem(); fe.Kind() {
43 + case reflect.Struct:
44 + fd := fe.FieldByName("sysfd")
45 + return syscall.Handle(fd.Uint()), nil
46 + }
47 + }
48 + return syscall.InvalidHandle, errInvalidConnType
49 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/iana.go new
+34
@@ -0,0 +1,34 @@
1 +// go generate gen.go
2 +// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3 +
4 +package ipv4
5 +
6 +// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
7 +const (
8 + ICMPTypeEchoReply ICMPType = 0 // Echo Reply
9 + ICMPTypeDestinationUnreachable ICMPType = 3 // Destination Unreachable
10 + ICMPTypeRedirect ICMPType = 5 // Redirect
11 + ICMPTypeEcho ICMPType = 8 // Echo
12 + ICMPTypeRouterAdvertisement ICMPType = 9 // Router Advertisement
13 + ICMPTypeRouterSolicitation ICMPType = 10 // Router Solicitation
14 + ICMPTypeTimeExceeded ICMPType = 11 // Time Exceeded
15 + ICMPTypeParameterProblem ICMPType = 12 // Parameter Problem
16 + ICMPTypeTimestamp ICMPType = 13 // Timestamp
17 + ICMPTypeTimestampReply ICMPType = 14 // Timestamp Reply
18 + ICMPTypePhoturis ICMPType = 40 // Photuris
19 +)
20 +
21 +// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
22 +var icmpTypes = map[ICMPType]string{
23 + 0: "echo reply",
24 + 3: "destination unreachable",
25 + 5: "redirect",
26 + 8: "echo",
27 + 9: "router advertisement",
28 + 10: "router solicitation",
29 + 11: "time exceeded",
30 + 12: "parameter problem",
31 + 13: "timestamp",
32 + 14: "timestamp reply",
33 + 40: "photuris",
34 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/icmp.go new
+16
@@ -0,0 +1,16 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +// An ICMPType represents a type of ICMP message.
8 +type ICMPType int
9 +
10 +func (typ ICMPType) String() string {
11 + s, ok := icmpTypes[typ]
12 + if !ok {
13 + return "<nil>"
14 + }
15 + return s
16 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/mocktransponder_test.go new
+21
@@ -0,0 +1,21 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "net"
9 + "testing"
10 +)
11 +
12 +func acceptor(t *testing.T, ln net.Listener, done chan<- bool) {
13 + defer func() { done <- true }()
14 +
15 + c, err := ln.Accept()
16 + if err != nil {
17 + t.Errorf("net.Listener.Accept failed: %v", err)
18 + return
19 + }
20 + c.Close()
21 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/multicast_test.go new
+267
@@ -0,0 +1,267 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "net"
9 + "os"
10 + "runtime"
11 + "testing"
12 + "time"
13 +
14 + "code.google.com/p/go.net/internal/icmp"
15 + "code.google.com/p/go.net/internal/nettest"
16 + "code.google.com/p/go.net/ipv4"
17 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
18 +)
19 +
20 +func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
21 + switch runtime.GOOS {
22 + case "nacl", "plan9", "solaris", "windows":
23 + t.Skipf("not supported on %q", runtime.GOOS)
24 + }
25 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
26 + if ifi == nil {
27 + t.Skipf("not available on %q", runtime.GOOS)
28 + }
29 +
30 + c, err := net.ListenPacket("udp4", "224.0.0.0:0") // see RFC 4727
31 + if err != nil {
32 + t.Fatalf("net.ListenPacket failed: %v", err)
33 + }
34 + defer c.Close()
35 +
36 + _, port, err := net.SplitHostPort(c.LocalAddr().String())
37 + if err != nil {
38 + t.Fatalf("net.SplitHostPort failed: %v", err)
39 + }
40 + dst, err := net.ResolveUDPAddr("udp4", "224.0.0.254:"+port) // see RFC 4727
41 + if err != nil {
42 + t.Fatalf("net.ResolveUDPAddr failed: %v", err)
43 + }
44 +
45 + p := ipv4.NewPacketConn(c)
46 + defer p.Close()
47 + if err := p.JoinGroup(ifi, dst); err != nil {
48 + t.Fatalf("ipv4.PacketConn.JoinGroup on %v failed: %v", ifi, err)
49 + }
50 + if err := p.SetMulticastInterface(ifi); err != nil {
51 + t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
52 + }
53 + if _, err := p.MulticastInterface(); err != nil {
54 + t.Fatalf("ipv4.PacketConn.MulticastInterface failed: %v", err)
55 + }
56 + if err := p.SetMulticastLoopback(true); err != nil {
57 + t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
58 + }
59 + if _, err := p.MulticastLoopback(); err != nil {
60 + t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
61 + }
62 + cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
63 +
64 + for i, toggle := range []bool{true, false, true} {
65 + if err := p.SetControlMessage(cf, toggle); err != nil {
66 + if protocolNotSupported(err) {
67 + t.Skipf("not supported on %q", runtime.GOOS)
68 + }
69 + t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
70 + }
71 + if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
72 + t.Fatalf("ipv4.PacketConn.SetDeadline failed: %v", err)
73 + }
74 + p.SetMulticastTTL(i + 1)
75 + if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), nil, dst); err != nil {
76 + t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
77 + }
78 + b := make([]byte, 128)
79 + if _, cm, _, err := p.ReadFrom(b); err != nil {
80 + t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
81 + } else {
82 + t.Logf("rcvd cmsg: %v", cm)
83 + }
84 + }
85 +}
86 +
87 +func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
88 + switch runtime.GOOS {
89 + case "nacl", "plan9", "solaris", "windows":
90 + t.Skipf("not supported on %q", runtime.GOOS)
91 + }
92 + if os.Getuid() != 0 {
93 + t.Skip("must be root")
94 + }
95 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
96 + if ifi == nil {
97 + t.Skipf("not available on %q", runtime.GOOS)
98 + }
99 +
100 + c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
101 + if err != nil {
102 + t.Fatalf("net.ListenPacket failed: %v", err)
103 + }
104 + defer c.Close()
105 +
106 + dst, err := net.ResolveIPAddr("ip4", "224.0.0.254") // see RFC 4727
107 + if err != nil {
108 + t.Fatalf("net.ResolveIPAddr failed: %v", err)
109 + }
110 +
111 + p := ipv4.NewPacketConn(c)
112 + defer p.Close()
113 + if err := p.JoinGroup(ifi, dst); err != nil {
114 + t.Fatalf("ipv4.PacketConn.JoinGroup on %v failed: %v", ifi, err)
115 + }
116 + if err := p.SetMulticastInterface(ifi); err != nil {
117 + t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
118 + }
119 + if _, err := p.MulticastInterface(); err != nil {
120 + t.Fatalf("ipv4.PacketConn.MulticastInterface failed: %v", err)
121 + }
122 + if err := p.SetMulticastLoopback(true); err != nil {
123 + t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
124 + }
125 + if _, err := p.MulticastLoopback(); err != nil {
126 + t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
127 + }
128 + cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
129 +
130 + for i, toggle := range []bool{true, false, true} {
131 + wb, err := (&icmp.Message{
132 + Type: ipv4.ICMPTypeEcho, Code: 0,
133 + Body: &icmp.Echo{
134 + ID: os.Getpid() & 0xffff, Seq: i + 1,
135 + Data: []byte("HELLO-R-U-THERE"),
136 + },
137 + }).Marshal(nil)
138 + if err != nil {
139 + t.Fatalf("icmp.Message.Marshal failed: %v", err)
140 + }
141 + if err := p.SetControlMessage(cf, toggle); err != nil {
142 + if protocolNotSupported(err) {
143 + t.Skipf("not supported on %q", runtime.GOOS)
144 + }
145 + t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
146 + }
147 + if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
148 + t.Fatalf("ipv4.PacketConn.SetDeadline failed: %v", err)
149 + }
150 + p.SetMulticastTTL(i + 1)
151 + if _, err := p.WriteTo(wb, nil, dst); err != nil {
152 + t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
153 + }
154 + b := make([]byte, 128)
155 + if n, cm, _, err := p.ReadFrom(b); err != nil {
156 + t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
157 + } else {
158 + t.Logf("rcvd cmsg: %v", cm)
159 + m, err := icmp.ParseMessage(iana.ProtocolICMP, b[:n])
160 + if err != nil {
161 + t.Fatalf("icmp.ParseMessage failed: %v", err)
162 + }
163 + switch {
164 + case m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1
165 + case m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0
166 + default:
167 + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
168 + }
169 + }
170 + }
171 +}
172 +
173 +func TestRawConnReadWriteMulticastICMP(t *testing.T) {
174 + if testing.Short() {
175 + t.Skip("to avoid external network")
176 + }
177 + if os.Getuid() != 0 {
178 + t.Skip("must be root")
179 + }
180 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
181 + if ifi == nil {
182 + t.Skipf("not available on %q", runtime.GOOS)
183 + }
184 +
185 + c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
186 + if err != nil {
187 + t.Fatalf("net.ListenPacket failed: %v", err)
188 + }
189 + defer c.Close()
190 +
191 + dst, err := net.ResolveIPAddr("ip4", "224.0.0.254") // see RFC 4727
192 + if err != nil {
193 + t.Fatalf("ResolveIPAddr failed: %v", err)
194 + }
195 +
196 + r, err := ipv4.NewRawConn(c)
197 + if err != nil {
198 + t.Fatalf("ipv4.NewRawConn failed: %v", err)
199 + }
200 + defer r.Close()
201 + if err := r.JoinGroup(ifi, dst); err != nil {
202 + t.Fatalf("ipv4.RawConn.JoinGroup on %v failed: %v", ifi, err)
203 + }
204 + if err := r.SetMulticastInterface(ifi); err != nil {
205 + t.Fatalf("ipv4.RawConn.SetMulticastInterface failed: %v", err)
206 + }
207 + if _, err := r.MulticastInterface(); err != nil {
208 + t.Fatalf("ipv4.RawConn.MulticastInterface failed: %v", err)
209 + }
210 + if err := r.SetMulticastLoopback(true); err != nil {
211 + t.Fatalf("ipv4.RawConn.SetMulticastLoopback failed: %v", err)
212 + }
213 + if _, err := r.MulticastLoopback(); err != nil {
214 + t.Fatalf("ipv4.RawConn.MulticastLoopback failed: %v", err)
215 + }
216 + cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
217 +
218 + for i, toggle := range []bool{true, false, true} {
219 + wb, err := (&icmp.Message{
220 + Type: ipv4.ICMPTypeEcho, Code: 0,
221 + Body: &icmp.Echo{
222 + ID: os.Getpid() & 0xffff, Seq: i + 1,
223 + Data: []byte("HELLO-R-U-THERE"),
224 + },
225 + }).Marshal(nil)
226 + if err != nil {
227 + t.Fatalf("icmp.Message.Marshal failed: %v", err)
228 + }
229 + wh := &ipv4.Header{
230 + Version: ipv4.Version,
231 + Len: ipv4.HeaderLen,
232 + TOS: i + 1,
233 + TotalLen: ipv4.HeaderLen + len(wb),
234 + Protocol: 1,
235 + Dst: dst.IP,
236 + }
237 + if err := r.SetControlMessage(cf, toggle); err != nil {
238 + if protocolNotSupported(err) {
239 + t.Skipf("not supported on %q", runtime.GOOS)
240 + }
241 + t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
242 + }
243 + if err := r.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
244 + t.Fatalf("ipv4.RawConn.SetDeadline failed: %v", err)
245 + }
246 + r.SetMulticastTTL(i + 1)
247 + if err := r.WriteTo(wh, wb, nil); err != nil {
248 + t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
249 + }
250 + rb := make([]byte, ipv4.HeaderLen+128)
251 + if rh, b, cm, err := r.ReadFrom(rb); err != nil {
252 + t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
253 + } else {
254 + t.Logf("rcvd cmsg: %v", cm)
255 + m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
256 + if err != nil {
257 + t.Fatalf("icmp.ParseMessage failed: %v", err)
258 + }
259 + switch {
260 + case (rh.Dst.IsLoopback() || rh.Dst.IsLinkLocalUnicast() || rh.Dst.IsGlobalUnicast()) && m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1
261 + case rh.Dst.IsMulticast() && m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0
262 + default:
263 + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
264 + }
265 + }
266 + }
267 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/multicastlistener_test.go new
+250
@@ -0,0 +1,250 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "net"
9 + "os"
10 + "runtime"
11 + "testing"
12 +
13 + "code.google.com/p/go.net/internal/nettest"
14 + "code.google.com/p/go.net/ipv4"
15 +)
16 +
17 +var udpMultipleGroupListenerTests = []net.Addr{
18 + &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}, // see RFC 4727
19 + &net.UDPAddr{IP: net.IPv4(224, 0, 0, 250)},
20 + &net.UDPAddr{IP: net.IPv4(224, 0, 0, 254)},
21 +}
22 +
23 +func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
24 + switch runtime.GOOS {
25 + case "nacl", "plan9", "solaris", "windows":
26 + t.Skipf("not supported on %q", runtime.GOOS)
27 + }
28 + if testing.Short() {
29 + t.Skip("to avoid external network")
30 + }
31 +
32 + for _, gaddr := range udpMultipleGroupListenerTests {
33 + c, err := net.ListenPacket("udp4", "0.0.0.0:0") // wildcard address with no reusable port
34 + if err != nil {
35 + t.Fatalf("net.ListenPacket failed: %v", err)
36 + }
37 + defer c.Close()
38 +
39 + p := ipv4.NewPacketConn(c)
40 + var mift []*net.Interface
41 +
42 + ift, err := net.Interfaces()
43 + if err != nil {
44 + t.Fatalf("net.Interfaces failed: %v", err)
45 + }
46 + for i, ifi := range ift {
47 + if _, ok := nettest.IsMulticastCapable("ip4", &ifi); !ok {
48 + continue
49 + }
50 + if err := p.JoinGroup(&ifi, gaddr); err != nil {
51 + t.Fatalf("ipv4.PacketConn.JoinGroup %v on %v failed: %v", gaddr, ifi, err)
52 + }
53 + mift = append(mift, &ift[i])
54 + }
55 + for _, ifi := range mift {
56 + if err := p.LeaveGroup(ifi, gaddr); err != nil {
57 + t.Fatalf("ipv4.PacketConn.LeaveGroup %v on %v failed: %v", gaddr, ifi, err)
58 + }
59 + }
60 + }
61 +}
62 +
63 +func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
64 + switch runtime.GOOS {
65 + case "nacl", "plan9", "solaris", "windows":
66 + t.Skipf("not supported on %q", runtime.GOOS)
67 + }
68 + if testing.Short() {
69 + t.Skip("to avoid external network")
70 + }
71 +
72 + for _, gaddr := range udpMultipleGroupListenerTests {
73 + c1, err := net.ListenPacket("udp4", "224.0.0.0:1024") // wildcard address with reusable port
74 + if err != nil {
75 + t.Fatalf("net.ListenPacket failed: %v", err)
76 + }
77 + defer c1.Close()
78 +
79 + c2, err := net.ListenPacket("udp4", "224.0.0.0:1024") // wildcard address with reusable port
80 + if err != nil {
81 + t.Fatalf("net.ListenPacket failed: %v", err)
82 + }
83 + defer c2.Close()
84 +
85 + var ps [2]*ipv4.PacketConn
86 + ps[0] = ipv4.NewPacketConn(c1)
87 + ps[1] = ipv4.NewPacketConn(c2)
88 + var mift []*net.Interface
89 +
90 + ift, err := net.Interfaces()
91 + if err != nil {
92 + t.Fatalf("net.Interfaces failed: %v", err)
93 + }
94 + for i, ifi := range ift {
95 + if _, ok := nettest.IsMulticastCapable("ip4", &ifi); !ok {
96 + continue
97 + }
98 + for _, p := range ps {
99 + if err := p.JoinGroup(&ifi, gaddr); err != nil {
100 + t.Fatalf("ipv4.PacketConn.JoinGroup %v on %v failed: %v", gaddr, ifi, err)
101 + }
102 + }
103 + mift = append(mift, &ift[i])
104 + }
105 + for _, ifi := range mift {
106 + for _, p := range ps {
107 + if err := p.LeaveGroup(ifi, gaddr); err != nil {
108 + t.Fatalf("ipv4.PacketConn.LeaveGroup %v on %v failed: %v", gaddr, ifi, err)
109 + }
110 + }
111 + }
112 + }
113 +}
114 +
115 +func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
116 + switch runtime.GOOS {
117 + case "nacl", "plan9", "solaris", "windows":
118 + t.Skipf("not supported on %q", runtime.GOOS)
119 + }
120 + if testing.Short() {
121 + t.Skip("to avoid external network")
122 + }
123 +
124 + gaddr := net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727
125 + type ml struct {
126 + c *ipv4.PacketConn
127 + ifi *net.Interface
128 + }
129 + var mlt []*ml
130 +
131 + ift, err := net.Interfaces()
132 + if err != nil {
133 + t.Fatalf("net.Interfaces failed: %v", err)
134 + }
135 + for i, ifi := range ift {
136 + ip, ok := nettest.IsMulticastCapable("ip4", &ifi)
137 + if !ok {
138 + continue
139 + }
140 + c, err := net.ListenPacket("udp4", ip.String()+":"+"1024") // unicast address with non-reusable port
141 + if err != nil {
142 + t.Fatalf("net.ListenPacket with %v failed: %v", ip, err)
143 + }
144 + defer c.Close()
145 + p := ipv4.NewPacketConn(c)
146 + if err := p.JoinGroup(&ifi, &gaddr); err != nil {
147 + t.Fatalf("ipv4.PacketConn.JoinGroup on %v failed: %v", ifi, err)
148 + }
149 + mlt = append(mlt, &ml{p, &ift[i]})
150 + }
151 + for _, m := range mlt {
152 + if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
153 + t.Fatalf("ipv4.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
154 + }
155 + }
156 +}
157 +
158 +func TestIPSingleRawConnWithSingleGroupListener(t *testing.T) {
159 + switch runtime.GOOS {
160 + case "nacl", "plan9", "solaris", "windows":
161 + t.Skipf("not supported on %q", runtime.GOOS)
162 + }
163 + if testing.Short() {
164 + t.Skip("to avoid external network")
165 + }
166 + if os.Getuid() != 0 {
167 + t.Skip("must be root")
168 + }
169 +
170 + c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") // wildcard address
171 + if err != nil {
172 + t.Fatalf("net.ListenPacket failed: %v", err)
173 + }
174 + defer c.Close()
175 +
176 + r, err := ipv4.NewRawConn(c)
177 + if err != nil {
178 + t.Fatalf("ipv4.RawConn failed: %v", err)
179 + }
180 + gaddr := net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727
181 + var mift []*net.Interface
182 +
183 + ift, err := net.Interfaces()
184 + if err != nil {
185 + t.Fatalf("net.Interfaces failed: %v", err)
186 + }
187 + for i, ifi := range ift {
188 + if _, ok := nettest.IsMulticastCapable("ip4", &ifi); !ok {
189 + continue
190 + }
191 + if err := r.JoinGroup(&ifi, &gaddr); err != nil {
192 + t.Fatalf("ipv4.RawConn.JoinGroup on %v failed: %v", ifi, err)
193 + }
194 + mift = append(mift, &ift[i])
195 + }
196 + for _, ifi := range mift {
197 + if err := r.LeaveGroup(ifi, &gaddr); err != nil {
198 + t.Fatalf("ipv4.RawConn.LeaveGroup on %v failed: %v", ifi, err)
199 + }
200 + }
201 +}
202 +
203 +func TestIPPerInterfaceSingleRawConnWithSingleGroupListener(t *testing.T) {
204 + switch runtime.GOOS {
205 + case "nacl", "plan9", "solaris", "windows":
206 + t.Skipf("not supported on %q", runtime.GOOS)
207 + }
208 + if testing.Short() {
209 + t.Skip("to avoid external network")
210 + }
211 + if os.Getuid() != 0 {
212 + t.Skip("must be root")
213 + }
214 +
215 + gaddr := net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727
216 + type ml struct {
217 + c *ipv4.RawConn
218 + ifi *net.Interface
219 + }
220 + var mlt []*ml
221 +
222 + ift, err := net.Interfaces()
223 + if err != nil {
224 + t.Fatalf("net.Interfaces failed: %v", err)
225 + }
226 + for i, ifi := range ift {
227 + ip, ok := nettest.IsMulticastCapable("ip4", &ifi)
228 + if !ok {
229 + continue
230 + }
231 + c, err := net.ListenPacket("ip4:253", ip.String()) // unicast address
232 + if err != nil {
233 + t.Fatalf("net.ListenPacket with %v failed: %v", ip, err)
234 + }
235 + defer c.Close()
236 + r, err := ipv4.NewRawConn(c)
237 + if err != nil {
238 + t.Fatalf("ipv4.NewRawConn failed: %v", err)
239 + }
240 + if err := r.JoinGroup(&ifi, &gaddr); err != nil {
241 + t.Fatalf("ipv4.RawConn.JoinGroup on %v failed: %v", ifi, err)
242 + }
243 + mlt = append(mlt, &ml{r, &ift[i]})
244 + }
245 + for _, m := range mlt {
246 + if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
247 + t.Fatalf("ipv4.RawConn.LeaveGroup on %v failed: %v", m.ifi, err)
248 + }
249 + }
250 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/multicastsockopt_test.go new
+113
@@ -0,0 +1,113 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "net"
9 + "os"
10 + "runtime"
11 + "testing"
12 +
13 + "code.google.com/p/go.net/internal/nettest"
14 + "code.google.com/p/go.net/ipv4"
15 +)
16 +
17 +var packetConnMulticastSocketOptionTests = []struct {
18 + net, proto, addr string
19 + gaddr net.Addr
20 +}{
21 + {"udp4", "", "224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}}, // see RFC 4727
22 + {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}}, // see RFC 4727
23 +}
24 +
25 +func TestPacketConnMulticastSocketOptions(t *testing.T) {
26 + switch runtime.GOOS {
27 + case "nacl", "plan9", "solaris":
28 + t.Skipf("not supported on %q", runtime.GOOS)
29 + }
30 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
31 + if ifi == nil {
32 + t.Skipf("not available on %q", runtime.GOOS)
33 + }
34 +
35 + for _, tt := range packetConnMulticastSocketOptionTests {
36 + if tt.net == "ip4" && os.Getuid() != 0 {
37 + t.Skip("must be root")
38 + }
39 + c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
40 + if err != nil {
41 + t.Fatalf("net.ListenPacket failed: %v", err)
42 + }
43 + defer c.Close()
44 +
45 + testMulticastSocketOptions(t, ipv4.NewPacketConn(c), ifi, tt.gaddr)
46 + }
47 +}
48 +
49 +func TestRawConnMulticastSocketOptions(t *testing.T) {
50 + switch runtime.GOOS {
51 + case "nacl", "plan9", "solaris":
52 + t.Skipf("not supported on %q", runtime.GOOS)
53 + }
54 + if os.Getuid() != 0 {
55 + t.Skip("must be root")
56 + }
57 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
58 + if ifi == nil {
59 + t.Skipf("not available on %q", runtime.GOOS)
60 + }
61 +
62 + c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
63 + if err != nil {
64 + t.Fatalf("net.ListenPacket failed: %v", err)
65 + }
66 + defer c.Close()
67 +
68 + r, err := ipv4.NewRawConn(c)
69 + if err != nil {
70 + t.Fatalf("ipv4.NewRawConn failed: %v", err)
71 + }
72 +
73 + testMulticastSocketOptions(t, r, ifi, &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}) /// see RFC 4727
74 +}
75 +
76 +type testIPv4MulticastConn interface {
77 + MulticastTTL() (int, error)
78 + SetMulticastTTL(ttl int) error
79 + MulticastLoopback() (bool, error)
80 + SetMulticastLoopback(bool) error
81 + JoinGroup(*net.Interface, net.Addr) error
82 + LeaveGroup(*net.Interface, net.Addr) error
83 +}
84 +
85 +func testMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, gaddr net.Addr) {
86 + const ttl = 255
87 + if err := c.SetMulticastTTL(ttl); err != nil {
88 + t.Fatalf("ipv4.PacketConn.SetMulticastTTL failed: %v", err)
89 + }
90 + if v, err := c.MulticastTTL(); err != nil {
91 + t.Fatalf("ipv4.PacketConn.MulticastTTL failed: %v", err)
92 + } else if v != ttl {
93 + t.Fatalf("got unexpected multicast TTL value %v; expected %v", v, ttl)
94 + }
95 +
96 + for _, toggle := range []bool{true, false} {
97 + if err := c.SetMulticastLoopback(toggle); err != nil {
98 + t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
99 + }
100 + if v, err := c.MulticastLoopback(); err != nil {
101 + t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
102 + } else if v != toggle {
103 + t.Fatalf("got unexpected multicast loopback %v; expected %v", v, toggle)
104 + }
105 + }
106 +
107 + if err := c.JoinGroup(ifi, gaddr); err != nil {
108 + t.Fatalf("ipv4.PacketConn.JoinGroup(%v, %v) failed: %v", ifi, gaddr, err)
109 + }
110 + if err := c.LeaveGroup(ifi, gaddr); err != nil {
111 + t.Fatalf("ipv4.PacketConn.LeaveGroup(%v, %v) failed: %v", ifi, gaddr, err)
112 + }
113 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/packet.go new
+97
@@ -0,0 +1,97 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +// A packetHandler represents the IPv4 datagram handler.
13 +type packetHandler struct {
14 + c *net.IPConn
15 + rawOpt
16 +}
17 +
18 +func (c *packetHandler) ok() bool { return c != nil && c.c != nil }
19 +
20 +// ReadFrom reads an IPv4 datagram from the endpoint c, copying the
21 +// datagram into b. It returns the received datagram as the IPv4
22 +// header h, the payload p and the control message cm.
23 +func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
24 + if !c.ok() {
25 + return nil, nil, nil, syscall.EINVAL
26 + }
27 + oob := newControlMessage(&c.rawOpt)
28 + n, oobn, _, src, err := c.c.ReadMsgIP(b, oob)
29 + if err != nil {
30 + return nil, nil, nil, err
31 + }
32 + var hs []byte
33 + if hs, p, err = slicePacket(b[:n]); err != nil {
34 + return nil, nil, nil, err
35 + }
36 + if h, err = ParseHeader(hs); err != nil {
37 + return nil, nil, nil, err
38 + }
39 + if cm, err = parseControlMessage(oob[:oobn]); err != nil {
40 + return nil, nil, nil, err
41 + }
42 + if src != nil && cm != nil {
43 + cm.Src = src.IP
44 + }
45 + return
46 +}
47 +
48 +func slicePacket(b []byte) (h, p []byte, err error) {
49 + if len(b) < HeaderLen {
50 + return nil, nil, errHeaderTooShort
51 + }
52 + hdrlen := int(b[0]&0x0f) << 2
53 + return b[:hdrlen], b[hdrlen:], nil
54 +}
55 +
56 +// WriteTo writes an IPv4 datagram through the endpoint c, copying the
57 +// datagram from the IPv4 header h and the payload p. The control
58 +// message cm allows the datagram path and the outgoing interface to be
59 +// specified. Currently only Darwin and Linux support this. The cm
60 +// may be nil if control of the outgoing datagram is not required.
61 +//
62 +// The IPv4 header h must contain appropriate fields that include:
63 +//
64 +// Version = ipv4.Version
65 +// Len = <must be specified>
66 +// TOS = <must be specified>
67 +// TotalLen = <must be specified>
68 +// ID = platform sets an appropriate value if ID is zero
69 +// FragOff = <must be specified>
70 +// TTL = <must be specified>
71 +// Protocol = <must be specified>
72 +// Checksum = platform sets an appropriate value if Checksum is zero
73 +// Src = platform sets an appropriate value if Src is nil
74 +// Dst = <must be specified>
75 +// Options = optional
76 +func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
77 + if !c.ok() {
78 + return syscall.EINVAL
79 + }
80 + oob := marshalControlMessage(cm)
81 + wh, err := h.Marshal()
82 + if err != nil {
83 + return err
84 + }
85 + dst := &net.IPAddr{}
86 + if cm != nil {
87 + if ip := cm.Dst.To4(); ip != nil {
88 + dst.IP = ip
89 + }
90 + }
91 + if dst.IP == nil {
92 + dst.IP = h.Dst
93 + }
94 + wh = append(wh, p...)
95 + _, _, err = c.c.WriteMsgIP(wh, oob, dst)
96 + return err
97 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/payload.go new
+15
@@ -0,0 +1,15 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import "net"
8 +
9 +// A payloadHandler represents the IPv4 datagram payload handler.
10 +type payloadHandler struct {
11 + net.PacketConn
12 + rawOpt
13 +}
14 +
15 +func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil }
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/payload_cmsg.go new
+75
@@ -0,0 +1,75 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build !plan9,!solaris,!windows
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// ReadFrom reads a payload of the received IPv4 datagram, from the
15 +// endpoint c, copying the payload into b. It returns the number of
16 +// bytes copied into b, the control message cm and the source address
17 +// src of the received datagram.
18 +func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
19 + if !c.ok() {
20 + return 0, nil, nil, syscall.EINVAL
21 + }
22 + oob := newControlMessage(&c.rawOpt)
23 + var oobn int
24 + switch c := c.PacketConn.(type) {
25 + case *net.UDPConn:
26 + if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
27 + return 0, nil, nil, err
28 + }
29 + case *net.IPConn:
30 + nb := make([]byte, maxHeaderLen+len(b))
31 + if n, oobn, _, src, err = c.ReadMsgIP(nb, oob); err != nil {
32 + return 0, nil, nil, err
33 + }
34 + hdrlen := int(nb[0]&0x0f) << 2
35 + copy(b, nb[hdrlen:])
36 + n -= hdrlen
37 + default:
38 + return 0, nil, nil, errInvalidConnType
39 + }
40 + if cm, err = parseControlMessage(oob[:oobn]); err != nil {
41 + return 0, nil, nil, err
42 + }
43 + if cm != nil {
44 + cm.Src = netAddrToIP4(src)
45 + }
46 + return
47 +}
48 +
49 +// WriteTo writes a payload of the IPv4 datagram, to the destination
50 +// address dst through the endpoint c, copying the payload from b. It
51 +// returns the number of bytes written. The control message cm allows
52 +// the datagram path and the outgoing interface to be specified.
53 +// Currently only Darwin and Darwin support this. The cm may be nil if
54 +// control of the outgoing datagram is not required.
55 +func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
56 + if !c.ok() {
57 + return 0, syscall.EINVAL
58 + }
59 + oob := marshalControlMessage(cm)
60 + if dst == nil {
61 + return 0, errMissingAddress
62 + }
63 + switch c := c.PacketConn.(type) {
64 + case *net.UDPConn:
65 + n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
66 + case *net.IPConn:
67 + n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
68 + default:
69 + return 0, errInvalidConnType
70 + }
71 + if err != nil {
72 + return 0, err
73 + }
74 + return
75 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/payload_nocmsg.go new
+42
@@ -0,0 +1,42 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build plan9 solaris windows
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// ReadFrom reads a payload of the received IPv4 datagram, from the
15 +// endpoint c, copying the payload into b. It returns the number of
16 +// bytes copied into b, the control message cm and the source address
17 +// src of the received datagram.
18 +func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
19 + if !c.ok() {
20 + return 0, nil, nil, syscall.EINVAL
21 + }
22 + if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
23 + return 0, nil, nil, err
24 + }
25 + return
26 +}
27 +
28 +// WriteTo writes a payload of the IPv4 datagram, to the destination
29 +// address dst through the endpoint c, copying the payload from b. It
30 +// returns the number of bytes written. The control message cm allows
31 +// the datagram path and the outgoing interface to be specified.
32 +// Currently only Darwin and Linux support this. The cm may be nil if
33 +// control of the outgoing datagram is not required.
34 +func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
35 + if !c.ok() {
36 + return 0, syscall.EINVAL
37 + }
38 + if dst == nil {
39 + return 0, errMissingAddress
40 + }
41 + return c.PacketConn.WriteTo(b, dst)
42 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt.go new
+37
@@ -0,0 +1,37 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +// Sticky socket options
8 +const (
9 + ssoTOS = iota // header field for unicast packet
10 + ssoTTL // header field for unicast packet
11 + ssoMulticastTTL // header field for multicast packet
12 + ssoMulticastInterface // outbound interface for multicast packet
13 + ssoMulticastLoopback // loopback for multicast packet
14 + ssoReceiveTTL // header field on received packet
15 + ssoReceiveDst // header field on received packet
16 + ssoReceiveInterface // inbound interface on received packet
17 + ssoPacketInfo // incbound or outbound packet path
18 + ssoHeaderPrepend // ipv4 header
19 + ssoJoinGroup // any-source multicast
20 + ssoLeaveGroup // any-source multicast
21 + ssoMax
22 +)
23 +
24 +// Sticky socket option value types
25 +const (
26 + ssoTypeByte = iota + 1
27 + ssoTypeInt
28 + ssoTypeInterface
29 + ssoTypeIPMreq
30 + ssoTypeIPMreqn
31 +)
32 +
33 +// A sockOpt represents a binding for sticky socket option.
34 +type sockOpt struct {
35 + name int // option name, must be equal or greater than 1
36 + typ int // option value type, must be equal or greater than 1
37 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_asmreq.go new
+83
@@ -0,0 +1,83 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd netbsd openbsd windows
6 +
7 +package ipv4
8 +
9 +import "net"
10 +
11 +func setIPMreqInterface(mreq *sysIPMreq, ifi *net.Interface) error {
12 + if ifi == nil {
13 + return nil
14 + }
15 + ifat, err := ifi.Addrs()
16 + if err != nil {
17 + return err
18 + }
19 + for _, ifa := range ifat {
20 + switch ifa := ifa.(type) {
21 + case *net.IPAddr:
22 + if ip := ifa.IP.To4(); ip != nil {
23 + copy(mreq.Interface[:], ip)
24 + return nil
25 + }
26 + case *net.IPNet:
27 + if ip := ifa.IP.To4(); ip != nil {
28 + copy(mreq.Interface[:], ip)
29 + return nil
30 + }
31 + }
32 + }
33 + return errNoSuchInterface
34 +}
35 +
36 +func netIP4ToInterface(ip net.IP) (*net.Interface, error) {
37 + ift, err := net.Interfaces()
38 + if err != nil {
39 + return nil, err
40 + }
41 + for _, ifi := range ift {
42 + ifat, err := ifi.Addrs()
43 + if err != nil {
44 + return nil, err
45 + }
46 + for _, ifa := range ifat {
47 + switch ifa := ifa.(type) {
48 + case *net.IPAddr:
49 + if ip.Equal(ifa.IP) {
50 + return &ifi, nil
51 + }
52 + case *net.IPNet:
53 + if ip.Equal(ifa.IP) {
54 + return &ifi, nil
55 + }
56 + }
57 + }
58 + }
59 + return nil, errNoSuchInterface
60 +}
61 +
62 +func netInterfaceToIP4(ifi *net.Interface) (net.IP, error) {
63 + if ifi == nil {
64 + return net.IPv4zero.To4(), nil
65 + }
66 + ifat, err := ifi.Addrs()
67 + if err != nil {
68 + return nil, err
69 + }
70 + for _, ifa := range ifat {
71 + switch ifa := ifa.(type) {
72 + case *net.IPAddr:
73 + if ip := ifa.IP.To4(); ip != nil {
74 + return ip, nil
75 + }
76 + case *net.IPNet:
77 + if ip := ifa.IP.To4(); ip != nil {
78 + return ip, nil
79 + }
80 + }
81 + }
82 + return nil, errNoSuchInterface
83 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_asmreq_stub.go new
+21
@@ -0,0 +1,21 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build !darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!windows
6 +
7 +package ipv4
8 +
9 +import "net"
10 +
11 +func setsockoptIPMreq(fd, name int, ifi *net.Interface, grp net.IP) error {
12 + return errOpNoSupport
13 +}
14 +
15 +func getsockoptInterface(fd, name int) (*net.Interface, error) {
16 + return nil, errOpNoSupport
17 +}
18 +
19 +func setsockoptInterface(fd, name int, ifi *net.Interface) error {
20 + return errOpNoSupport
21 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_asmreq_unix.go new
+46
@@ -0,0 +1,46 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd netbsd openbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "os"
12 + "unsafe"
13 +
14 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
15 +)
16 +
17 +func setsockoptIPMreq(fd, name int, ifi *net.Interface, grp net.IP) error {
18 + mreq := sysIPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
19 + if err := setIPMreqInterface(&mreq, ifi); err != nil {
20 + return err
21 + }
22 + return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreq), sysSizeofIPMreq))
23 +}
24 +
25 +func getsockoptInterface(fd, name int) (*net.Interface, error) {
26 + var b [4]byte
27 + l := sysSockoptLen(4)
28 + if err := getsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), &l); err != nil {
29 + return nil, os.NewSyscallError("getsockopt", err)
30 + }
31 + ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
32 + if err != nil {
33 + return nil, err
34 + }
35 + return ifi, nil
36 +}
37 +
38 +func setsockoptInterface(fd, name int, ifi *net.Interface) error {
39 + ip, err := netInterfaceToIP4(ifi)
40 + if err != nil {
41 + return err
42 + }
43 + var b [4]byte
44 + copy(b[:], ip)
45 + return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), sysSockoptLen(4)))
46 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_asmreq_windows.go new
+45
@@ -0,0 +1,45 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "os"
10 + "syscall"
11 + "unsafe"
12 +
13 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
14 +)
15 +
16 +func setsockoptIPMreq(fd syscall.Handle, name int, ifi *net.Interface, grp net.IP) error {
17 + mreq := sysIPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
18 + if err := setIPMreqInterface(&mreq, ifi); err != nil {
19 + return err
20 + }
21 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofIPMreq)))
22 +}
23 +
24 +func getsockoptInterface(fd syscall.Handle, name int) (*net.Interface, error) {
25 + var b [4]byte
26 + l := int32(4)
27 + if err := syscall.Getsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&b[0])), &l); err != nil {
28 + return nil, os.NewSyscallError("getsockopt", err)
29 + }
30 + ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
31 + if err != nil {
32 + return nil, err
33 + }
34 + return ifi, nil
35 +}
36 +
37 +func setsockoptInterface(fd syscall.Handle, name int, ifi *net.Interface) error {
38 + ip, err := netInterfaceToIP4(ifi)
39 + if err != nil {
40 + return err
41 + }
42 + var b [4]byte
43 + copy(b[:], ip)
44 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&b[0])), 4))
45 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_asmreqn_stub.go new
+17
@@ -0,0 +1,17 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build !darwin,!freebsd,!linux,!windows
6 +
7 +package ipv4
8 +
9 +import "net"
10 +
11 +func getsockoptIPMreqn(fd, name int) (*net.Interface, error) {
12 + return nil, errOpNoSupport
13 +}
14 +
15 +func setsockoptIPMreqn(fd, name int, ifi *net.Interface, grp net.IP) error {
16 + return errOpNoSupport
17 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_asmreqn_unix.go new
+42
@@ -0,0 +1,42 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin freebsd linux
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "os"
12 + "unsafe"
13 +
14 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
15 +)
16 +
17 +func getsockoptIPMreqn(fd, name int) (*net.Interface, error) {
18 + var mreqn sysIPMreqn
19 + l := sysSockoptLen(sysSizeofIPMreqn)
20 + if err := getsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), &l); err != nil {
21 + return nil, os.NewSyscallError("getsockopt", err)
22 + }
23 + if mreqn.Ifindex == 0 {
24 + return nil, nil
25 + }
26 + ifi, err := net.InterfaceByIndex(int(mreqn.Ifindex))
27 + if err != nil {
28 + return nil, err
29 + }
30 + return ifi, nil
31 +}
32 +
33 +func setsockoptIPMreqn(fd, name int, ifi *net.Interface, grp net.IP) error {
34 + var mreqn sysIPMreqn
35 + if ifi != nil {
36 + mreqn.Ifindex = int32(ifi.Index)
37 + }
38 + if grp != nil {
39 + mreqn.Multiaddr = [4]byte{grp[0], grp[1], grp[2], grp[3]}
40 + }
41 + return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), sysSizeofIPMreqn))
42 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_stub.go new
+29
@@ -0,0 +1,29 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv4
8 +
9 +import "net"
10 +
11 +func getInt(fd int, opt *sockOpt) (int, error) {
12 + return 0, errOpNoSupport
13 +}
14 +
15 +func setInt(fd int, opt *sockOpt, v int) error {
16 + return errOpNoSupport
17 +}
18 +
19 +func getInterface(fd int, opt *sockOpt) (*net.Interface, error) {
20 + return nil, errOpNoSupport
21 +}
22 +
23 +func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error {
24 + return errOpNoSupport
25 +}
26 +
27 +func setGroup(fd int, opt *sockOpt, ifi *net.Interface, ip net.IP) error {
28 + return errOpNoSupport
29 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_unix.go new
+94
@@ -0,0 +1,94 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "os"
12 + "unsafe"
13 +
14 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
15 +)
16 +
17 +func getInt(fd int, opt *sockOpt) (int, error) {
18 + if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) {
19 + return 0, errOpNoSupport
20 + }
21 + var i int32
22 + var b byte
23 + p := unsafe.Pointer(&i)
24 + l := sysSockoptLen(4)
25 + if opt.typ == ssoTypeByte {
26 + p = unsafe.Pointer(&b)
27 + l = sysSockoptLen(1)
28 + }
29 + if err := getsockopt(fd, iana.ProtocolIP, opt.name, p, &l); err != nil {
30 + return 0, os.NewSyscallError("getsockopt", err)
31 + }
32 + if opt.typ == ssoTypeByte {
33 + return int(b), nil
34 + }
35 + return int(i), nil
36 +}
37 +
38 +func setInt(fd int, opt *sockOpt, v int) error {
39 + if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) {
40 + return errOpNoSupport
41 + }
42 + i := int32(v)
43 + var b byte
44 + p := unsafe.Pointer(&i)
45 + l := sysSockoptLen(4)
46 + if opt.typ == ssoTypeByte {
47 + b = byte(v)
48 + p = unsafe.Pointer(&b)
49 + l = sysSockoptLen(1)
50 + }
51 + return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, opt.name, p, l))
52 +}
53 +
54 +func getInterface(fd int, opt *sockOpt) (*net.Interface, error) {
55 + if opt.name < 1 {
56 + return nil, errOpNoSupport
57 + }
58 + switch opt.typ {
59 + case ssoTypeInterface:
60 + return getsockoptInterface(fd, opt.name)
61 + case ssoTypeIPMreqn:
62 + return getsockoptIPMreqn(fd, opt.name)
63 + default:
64 + return nil, errOpNoSupport
65 + }
66 +}
67 +
68 +func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error {
69 + if opt.name < 1 {
70 + return errOpNoSupport
71 + }
72 + switch opt.typ {
73 + case ssoTypeInterface:
74 + return setsockoptInterface(fd, opt.name, ifi)
75 + case ssoTypeIPMreqn:
76 + return setsockoptIPMreqn(fd, opt.name, ifi, nil)
77 + default:
78 + return errOpNoSupport
79 + }
80 +}
81 +
82 +func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
83 + if opt.name < 1 {
84 + return errOpNoSupport
85 + }
86 + switch opt.typ {
87 + case ssoTypeIPMreq:
88 + return setsockoptIPMreq(fd, opt.name, ifi, grp)
89 + case ssoTypeIPMreqn:
90 + return setsockoptIPMreqn(fd, opt.name, ifi, grp)
91 + default:
92 + return errOpNoSupport
93 + }
94 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sockopt_windows.go new
+55
@@ -0,0 +1,55 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "os"
10 + "syscall"
11 + "unsafe"
12 +
13 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
14 +)
15 +
16 +func getInt(fd syscall.Handle, opt *sockOpt) (int, error) {
17 + if opt.name < 1 || opt.typ != ssoTypeInt {
18 + return 0, errOpNoSupport
19 + }
20 + var i int32
21 + l := int32(4)
22 + if err := syscall.Getsockopt(fd, iana.ProtocolIP, int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil {
23 + return 0, os.NewSyscallError("getsockopt", err)
24 + }
25 + return int(i), nil
26 +}
27 +
28 +func setInt(fd syscall.Handle, opt *sockOpt, v int) error {
29 + if opt.name < 1 || opt.typ != ssoTypeInt {
30 + return errOpNoSupport
31 + }
32 + i := int32(v)
33 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4))
34 +}
35 +
36 +func getInterface(fd syscall.Handle, opt *sockOpt) (*net.Interface, error) {
37 + if opt.name < 1 || opt.typ != ssoTypeInterface {
38 + return nil, errOpNoSupport
39 + }
40 + return getsockoptInterface(fd, opt.name)
41 +}
42 +
43 +func setInterface(fd syscall.Handle, opt *sockOpt, ifi *net.Interface) error {
44 + if opt.name < 1 || opt.typ != ssoTypeInterface {
45 + return errOpNoSupport
46 + }
47 + return setsockoptInterface(fd, opt.name, ifi)
48 +}
49 +
50 +func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
51 + if opt.name < 1 || opt.typ != ssoTypeIPMreq {
52 + return errOpNoSupport
53 + }
54 + return setsockoptIPMreq(fd, opt.name, ifi, grp)
55 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_bsd.go new
+36
@@ -0,0 +1,36 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build dragonfly netbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +type sysSockoptLen int32
15 +
16 +var (
17 + ctlOpts = [ctlMax]ctlOpt{
18 + ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
19 + ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
20 + ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
21 + }
22 +
23 + sockOpts = [ssoMax]sockOpt{
24 + ssoTOS: {sysIP_TOS, ssoTypeInt},
25 + ssoTTL: {sysIP_TTL, ssoTypeInt},
26 + ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
27 + ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
28 + ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
29 + ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
30 + ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
31 + ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
32 + ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
33 + ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
34 + ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
35 + }
36 +)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_darwin.go new
+64
@@ -0,0 +1,64 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +type sysSockoptLen int32
13 +
14 +var (
15 + ctlOpts = [ctlMax]ctlOpt{
16 + ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
17 + ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
18 + ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
19 + }
20 +
21 + sockOpts = [ssoMax]sockOpt{
22 + ssoTOS: {sysIP_TOS, ssoTypeInt},
23 + ssoTTL: {sysIP_TTL, ssoTypeInt},
24 + ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
25 + ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
26 + ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
27 + ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
28 + ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
29 + ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
30 + ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
31 + ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
32 + ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
33 + }
34 +)
35 +
36 +func init() {
37 + // Seems like kern.osreldate is veiled on latest OS X. We use
38 + // kern.osrelease instead.
39 + osver, err := syscall.Sysctl("kern.osrelease")
40 + if err != nil {
41 + return
42 + }
43 + var i int
44 + for i = range osver {
45 + if osver[i] != '.' {
46 + continue
47 + }
48 + }
49 + // The IP_PKTINFO was introduced in OS X 10.7 (Darwin
50 + // 11.0.0). See http://support.apple.com/kb/HT1633.
51 + if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
52 + ctlOpts[ctlPacketInfo].name = sysIP_PKTINFO
53 + ctlOpts[ctlPacketInfo].length = sysSizeofInetPktinfo
54 + ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo
55 + ctlOpts[ctlPacketInfo].parse = parsePacketInfo
56 + sockOpts[ssoPacketInfo].name = sysIP_RECVPKTINFO
57 + sockOpts[ssoPacketInfo].typ = ssoTypeInt
58 + sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn
59 + }
60 +}
61 +
62 +func (pi *sysInetPktinfo) setIfindex(i int) {
63 + pi.Ifindex = uint32(i)
64 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_freebsd.go new
+41
@@ -0,0 +1,41 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +type sysSockoptLen int32
13 +
14 +var (
15 + ctlOpts = [ctlMax]ctlOpt{
16 + ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
17 + ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
18 + ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
19 + }
20 +
21 + sockOpts = [ssoMax]sockOpt{
22 + ssoTOS: {sysIP_TOS, ssoTypeInt},
23 + ssoTTL: {sysIP_TTL, ssoTypeInt},
24 + ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
25 + ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
26 + ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
27 + ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
28 + ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
29 + ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
30 + ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
31 + ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
32 + ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
33 + }
34 +)
35 +
36 +func init() {
37 + freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate")
38 + if freebsdVersion >= 1000000 {
39 + sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn
40 + }
41 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_linux.go new
+31
@@ -0,0 +1,31 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +type sysSockoptLen int32
8 +
9 +var (
10 + ctlOpts = [ctlMax]ctlOpt{
11 + ctlTTL: {sysIP_TTL, 1, marshalTTL, parseTTL},
12 + ctlPacketInfo: {sysIP_PKTINFO, sysSizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
13 + }
14 +
15 + sockOpts = [ssoMax]sockOpt{
16 + ssoTOS: {sysIP_TOS, ssoTypeInt},
17 + ssoTTL: {sysIP_TTL, ssoTypeInt},
18 + ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeInt},
19 + ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeIPMreqn},
20 + ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
21 + ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
22 + ssoPacketInfo: {sysIP_PKTINFO, ssoTypeInt},
23 + ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
24 + ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreqn},
25 + ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreqn},
26 + }
27 +)
28 +
29 +func (pi *sysInetPktinfo) setIfindex(i int) {
30 + pi.Ifindex = int32(i)
31 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_openbsd.go new
+34
@@ -0,0 +1,34 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +type sysSockoptLen int32
13 +
14 +var (
15 + ctlOpts = [ctlMax]ctlOpt{
16 + ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
17 + ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
18 + ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
19 + }
20 +
21 + sockOpts = [ssoMax]sockOpt{
22 + ssoTOS: {sysIP_TOS, ssoTypeInt},
23 + ssoTTL: {sysIP_TTL, ssoTypeInt},
24 + ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
25 + ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
26 + ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeByte},
27 + ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
28 + ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
29 + ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
30 + ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
31 + ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
32 + ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
33 + }
34 +)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_stub.go new
+15
@@ -0,0 +1,15 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv4
8 +
9 +type sysSockoptLen int32
10 +
11 +var (
12 + ctlOpts = [ctlMax]ctlOpt{}
13 +
14 + sockOpts = [ssoMax]sockOpt{}
15 +)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/sys_windows.go new
+61
@@ -0,0 +1,61 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +const (
8 + // See ws2tcpip.h.
9 + sysIP_OPTIONS = 0x1
10 + sysIP_HDRINCL = 0x2
11 + sysIP_TOS = 0x3
12 + sysIP_TTL = 0x4
13 + sysIP_MULTICAST_IF = 0x9
14 + sysIP_MULTICAST_TTL = 0xa
15 + sysIP_MULTICAST_LOOP = 0xb
16 + sysIP_ADD_MEMBERSHIP = 0xc
17 + sysIP_DROP_MEMBERSHIP = 0xd
18 + sysIP_DONTFRAGMENT = 0xe
19 + sysIP_ADD_SOURCE_MEMBERSHIP = 0xf
20 + sysIP_DROP_SOURCE_MEMBERSHIP = 0x10
21 + sysIP_PKTINFO = 0x13
22 +
23 + sysSizeofInetPktinfo = 0x8
24 + sysSizeofIPMreq = 0x8
25 + sysSizeofIPMreqSource = 0xc
26 +)
27 +
28 +type sysInetPktinfo struct {
29 + Addr [4]byte
30 + Ifindex int32
31 +}
32 +
33 +type sysIPMreq struct {
34 + Multiaddr [4]byte
35 + Interface [4]byte
36 +}
37 +
38 +type sysIPMreqSource struct {
39 + Multiaddr [4]byte
40 + Sourceaddr [4]byte
41 + Interface [4]byte
42 +}
43 +
44 +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms738586(v=vs.85).aspx
45 +var (
46 + ctlOpts = [ctlMax]ctlOpt{}
47 +
48 + sockOpts = [ssoMax]sockOpt{
49 + ssoTOS: {sysIP_TOS, ssoTypeInt},
50 + ssoTTL: {sysIP_TTL, ssoTypeInt},
51 + ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeInt},
52 + ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
53 + ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
54 + ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
55 + ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
56 + }
57 +)
58 +
59 +func (pi *sysInetPktinfo) setIfindex(i int) {
60 + pi.Ifindex = int32(i)
61 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/syscall_linux_386.go new
+31
@@ -0,0 +1,31 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4
6 +
7 +import (
8 + "syscall"
9 + "unsafe"
10 +)
11 +
12 +const (
13 + sysGETSOCKOPT = 0xf
14 + sysSETSOCKOPT = 0xe
15 +)
16 +
17 +func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
18 +
19 +func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
20 + if _, errno := socketcall(sysGETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
21 + return error(errno)
22 + }
23 + return nil
24 +}
25 +
26 +func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
27 + if _, errno := socketcall(sysSETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
28 + return error(errno)
29 + }
30 + return nil
31 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/syscall_unix.go new
+26
@@ -0,0 +1,26 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux,amd64 linux,arm netbsd openbsd
6 +
7 +package ipv4
8 +
9 +import (
10 + "syscall"
11 + "unsafe"
12 +)
13 +
14 +func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
15 + if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
16 + return error(errno)
17 + }
18 + return nil
19 +}
20 +
21 +func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
22 + if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
23 + return error(errno)
24 + }
25 + return nil
26 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/thunk_linux_386.s new
+8
@@ -0,0 +1,8 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build go1.2
6 +
7 +TEXT ·socketcall(SB),4,$0-36
8 + JMP syscall·socketcall(SB)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/unicast_test.go new
+300
@@ -0,0 +1,300 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "net"
9 + "os"
10 + "runtime"
11 + "testing"
12 + "time"
13 +
14 + "code.google.com/p/go.net/internal/icmp"
15 + "code.google.com/p/go.net/internal/nettest"
16 + "code.google.com/p/go.net/ipv4"
17 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
18 +)
19 +
20 +func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
21 + c, err := net.ListenPacket("udp4", "127.0.0.1:0")
22 + if err != nil {
23 + return nil, nil, err
24 + }
25 + dst, err := net.ResolveUDPAddr("udp4", c.LocalAddr().String())
26 + if err != nil {
27 + c.Close()
28 + return nil, nil, err
29 + }
30 + return c, dst, nil
31 +}
32 +
33 +func BenchmarkReadWriteNetUDP(b *testing.B) {
34 + c, dst, err := benchmarkUDPListener()
35 + if err != nil {
36 + b.Fatalf("benchmarkUDPListener failed: %v", err)
37 + }
38 + defer c.Close()
39 +
40 + wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
41 + b.ResetTimer()
42 + for i := 0; i < b.N; i++ {
43 + benchmarkReadWriteNetUDP(b, c, wb, rb, dst)
44 + }
45 +}
46 +
47 +func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) {
48 + if _, err := c.WriteTo(wb, dst); err != nil {
49 + b.Fatalf("net.PacketConn.WriteTo failed: %v", err)
50 + }
51 + if _, _, err := c.ReadFrom(rb); err != nil {
52 + b.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
53 + }
54 +}
55 +
56 +func BenchmarkReadWriteIPv4UDP(b *testing.B) {
57 + c, dst, err := benchmarkUDPListener()
58 + if err != nil {
59 + b.Fatalf("benchmarkUDPListener failed: %v", err)
60 + }
61 + defer c.Close()
62 +
63 + p := ipv4.NewPacketConn(c)
64 + defer p.Close()
65 + cf := ipv4.FlagTTL | ipv4.FlagInterface
66 + if err := p.SetControlMessage(cf, true); err != nil {
67 + b.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
68 + }
69 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
70 +
71 + wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
72 + b.ResetTimer()
73 + for i := 0; i < b.N; i++ {
74 + benchmarkReadWriteIPv4UDP(b, p, wb, rb, dst, ifi)
75 + }
76 +}
77 +
78 +func benchmarkReadWriteIPv4UDP(b *testing.B, p *ipv4.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) {
79 + cm := ipv4.ControlMessage{TTL: 1}
80 + if ifi != nil {
81 + cm.IfIndex = ifi.Index
82 + }
83 + if _, err := p.WriteTo(wb, &cm, dst); err != nil {
84 + b.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
85 + }
86 + if _, _, _, err := p.ReadFrom(rb); err != nil {
87 + b.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
88 + }
89 +}
90 +
91 +func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
92 + switch runtime.GOOS {
93 + case "nacl", "plan9", "solaris", "windows":
94 + t.Skipf("not supported on %q", runtime.GOOS)
95 + }
96 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
97 + if ifi == nil {
98 + t.Skipf("not available on %q", runtime.GOOS)
99 + }
100 +
101 + c, err := net.ListenPacket("udp4", "127.0.0.1:0")
102 + if err != nil {
103 + t.Fatalf("net.ListenPacket failed: %v", err)
104 + }
105 + defer c.Close()
106 +
107 + dst, err := net.ResolveUDPAddr("udp4", c.LocalAddr().String())
108 + if err != nil {
109 + t.Fatalf("net.ResolveUDPAddr failed: %v", err)
110 + }
111 + p := ipv4.NewPacketConn(c)
112 + defer p.Close()
113 + cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
114 +
115 + for i, toggle := range []bool{true, false, true} {
116 + if err := p.SetControlMessage(cf, toggle); err != nil {
117 + if protocolNotSupported(err) {
118 + t.Skipf("not supported on %q", runtime.GOOS)
119 + }
120 + t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
121 + }
122 + p.SetTTL(i + 1)
123 + if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
124 + t.Fatalf("ipv4.PacketConn.SetWriteDeadline failed: %v", err)
125 + }
126 + if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), nil, dst); err != nil {
127 + t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
128 + }
129 + rb := make([]byte, 128)
130 + if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
131 + t.Fatalf("ipv4.PacketConn.SetReadDeadline failed: %v", err)
132 + }
133 + if _, cm, _, err := p.ReadFrom(rb); err != nil {
134 + t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
135 + } else {
136 + t.Logf("rcvd cmsg: %v", cm)
137 + }
138 + }
139 +}
140 +
141 +func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
142 + switch runtime.GOOS {
143 + case "nacl", "plan9", "solaris", "windows":
144 + t.Skipf("not supported on %q", runtime.GOOS)
145 + }
146 + if os.Getuid() != 0 {
147 + t.Skip("must be root")
148 + }
149 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
150 + if ifi == nil {
151 + t.Skipf("not available on %q", runtime.GOOS)
152 + }
153 +
154 + c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
155 + if err != nil {
156 + t.Fatalf("net.ListenPacket failed: %v", err)
157 + }
158 + defer c.Close()
159 +
160 + dst, err := net.ResolveIPAddr("ip4", "127.0.0.1")
161 + if err != nil {
162 + t.Fatalf("ResolveIPAddr failed: %v", err)
163 + }
164 + p := ipv4.NewPacketConn(c)
165 + defer p.Close()
166 + cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
167 +
168 + for i, toggle := range []bool{true, false, true} {
169 + wb, err := (&icmp.Message{
170 + Type: ipv4.ICMPTypeEcho, Code: 0,
171 + Body: &icmp.Echo{
172 + ID: os.Getpid() & 0xffff, Seq: i + 1,
173 + Data: []byte("HELLO-R-U-THERE"),
174 + },
175 + }).Marshal(nil)
176 + if err != nil {
177 + t.Fatalf("icmp.Message.Marshal failed: %v", err)
178 + }
179 + if err := p.SetControlMessage(cf, toggle); err != nil {
180 + if protocolNotSupported(err) {
181 + t.Skipf("not supported on %q", runtime.GOOS)
182 + }
183 + t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
184 + }
185 + p.SetTTL(i + 1)
186 + if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
187 + t.Fatalf("ipv4.PacketConn.SetWriteDeadline failed: %v", err)
188 + }
189 + if _, err := p.WriteTo(wb, nil, dst); err != nil {
190 + t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
191 + }
192 + b := make([]byte, 128)
193 + loop:
194 + if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
195 + t.Fatalf("ipv4.PacketConn.SetReadDeadline failed: %v", err)
196 + }
197 + if n, cm, _, err := p.ReadFrom(b); err != nil {
198 + t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
199 + } else {
200 + t.Logf("rcvd cmsg: %v", cm)
201 + m, err := icmp.ParseMessage(iana.ProtocolICMP, b[:n])
202 + if err != nil {
203 + t.Fatalf("icmp.ParseMessage failed: %v", err)
204 + }
205 + if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
206 + // On Linux we must handle own sent packets.
207 + goto loop
208 + }
209 + if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
210 + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
211 + }
212 + }
213 + }
214 +}
215 +
216 +func TestRawConnReadWriteUnicastICMP(t *testing.T) {
217 + switch runtime.GOOS {
218 + case "nacl", "plan9", "solaris", "windows":
219 + t.Skipf("not supported on %q", runtime.GOOS)
220 + }
221 + if os.Getuid() != 0 {
222 + t.Skip("must be root")
223 + }
224 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
225 + if ifi == nil {
226 + t.Skipf("not available on %q", runtime.GOOS)
227 + }
228 +
229 + c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
230 + if err != nil {
231 + t.Fatalf("net.ListenPacket failed: %v", err)
232 + }
233 + defer c.Close()
234 +
235 + dst, err := net.ResolveIPAddr("ip4", "127.0.0.1")
236 + if err != nil {
237 + t.Fatalf("ResolveIPAddr failed: %v", err)
238 + }
239 + r, err := ipv4.NewRawConn(c)
240 + if err != nil {
241 + t.Fatalf("ipv4.NewRawConn failed: %v", err)
242 + }
243 + defer r.Close()
244 + cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
245 +
246 + for i, toggle := range []bool{true, false, true} {
247 + wb, err := (&icmp.Message{
248 + Type: ipv4.ICMPTypeEcho, Code: 0,
249 + Body: &icmp.Echo{
250 + ID: os.Getpid() & 0xffff, Seq: i + 1,
251 + Data: []byte("HELLO-R-U-THERE"),
252 + },
253 + }).Marshal(nil)
254 + if err != nil {
255 + t.Fatalf("icmp.Message.Marshal failed: %v", err)
256 + }
257 + wh := &ipv4.Header{
258 + Version: ipv4.Version,
259 + Len: ipv4.HeaderLen,
260 + TOS: i + 1,
261 + TotalLen: ipv4.HeaderLen + len(wb),
262 + TTL: i + 1,
263 + Protocol: 1,
264 + Dst: dst.IP,
265 + }
266 + if err := r.SetControlMessage(cf, toggle); err != nil {
267 + if protocolNotSupported(err) {
268 + t.Skipf("not supported on %q", runtime.GOOS)
269 + }
270 + t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
271 + }
272 + if err := r.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
273 + t.Fatalf("ipv4.RawConn.SetWriteDeadline failed: %v", err)
274 + }
275 + if err := r.WriteTo(wh, wb, nil); err != nil {
276 + t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
277 + }
278 + rb := make([]byte, ipv4.HeaderLen+128)
279 + loop:
280 + if err := r.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
281 + t.Fatalf("ipv4.RawConn.SetReadDeadline failed: %v", err)
282 + }
283 + if _, b, cm, err := r.ReadFrom(rb); err != nil {
284 + t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
285 + } else {
286 + t.Logf("rcvd cmsg: %v", cm)
287 + m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
288 + if err != nil {
289 + t.Fatalf("icmp.ParseMessage failed: %v", err)
290 + }
291 + if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
292 + // On Linux we must handle own sent packets.
293 + goto loop
294 + }
295 + if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
296 + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
297 + }
298 + }
299 + }
300 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/unicastsockopt_test.go new
+138
@@ -0,0 +1,138 @@
1 +// Copyright 2012 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv4_test
6 +
7 +import (
8 + "net"
9 + "os"
10 + "runtime"
11 + "testing"
12 +
13 + "code.google.com/p/go.net/internal/nettest"
14 + "code.google.com/p/go.net/ipv4"
15 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/internal/iana"
16 +)
17 +
18 +func TestConnUnicastSocketOptions(t *testing.T) {
19 + switch runtime.GOOS {
20 + case "nacl", "plan9", "solaris":
21 + t.Skipf("not supported on %q", runtime.GOOS)
22 + }
23 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
24 + if ifi == nil {
25 + t.Skipf("not available on %q", runtime.GOOS)
26 + }
27 +
28 + ln, err := net.Listen("tcp4", "127.0.0.1:0")
29 + if err != nil {
30 + t.Fatalf("net.Listen failed: %v", err)
31 + }
32 + defer ln.Close()
33 +
34 + done := make(chan bool)
35 + go acceptor(t, ln, done)
36 +
37 + c, err := net.Dial("tcp4", ln.Addr().String())
38 + if err != nil {
39 + t.Fatalf("net.Dial failed: %v", err)
40 + }
41 + defer c.Close()
42 +
43 + testUnicastSocketOptions(t, ipv4.NewConn(c))
44 +
45 + <-done
46 +}
47 +
48 +var packetConnUnicastSocketOptionTests = []struct {
49 + net, proto, addr string
50 +}{
51 + {"udp4", "", "127.0.0.1:0"},
52 + {"ip4", ":icmp", "127.0.0.1"},
53 +}
54 +
55 +func TestPacketConnUnicastSocketOptions(t *testing.T) {
56 + switch runtime.GOOS {
57 + case "nacl", "plan9", "solaris":
58 + t.Skipf("not supported on %q", runtime.GOOS)
59 + }
60 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
61 + if ifi == nil {
62 + t.Skipf("not available on %q", runtime.GOOS)
63 + }
64 +
65 + for _, tt := range packetConnUnicastSocketOptionTests {
66 + if tt.net == "ip4" && os.Getuid() != 0 {
67 + t.Skip("must be root")
68 + }
69 + c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
70 + if err != nil {
71 + t.Fatalf("net.ListenPacket(%q, %q) failed: %v", tt.net+tt.proto, tt.addr, err)
72 + }
73 + defer c.Close()
74 +
75 + testUnicastSocketOptions(t, ipv4.NewPacketConn(c))
76 + }
77 +}
78 +
79 +func TestRawConnUnicastSocketOptions(t *testing.T) {
80 + switch runtime.GOOS {
81 + case "nacl", "plan9", "solaris":
82 + t.Skipf("not supported on %q", runtime.GOOS)
83 + }
84 + if os.Getuid() != 0 {
85 + t.Skip("must be root")
86 + }
87 + ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
88 + if ifi == nil {
89 + t.Skipf("not available on %q", runtime.GOOS)
90 + }
91 +
92 + c, err := net.ListenPacket("ip4:icmp", "127.0.0.1")
93 + if err != nil {
94 + t.Fatalf("net.ListenPacket failed: %v", err)
95 + }
96 + defer c.Close()
97 +
98 + r, err := ipv4.NewRawConn(c)
99 + if err != nil {
100 + t.Fatalf("ipv4.NewRawConn failed: %v", err)
101 + }
102 +
103 + testUnicastSocketOptions(t, r)
104 +}
105 +
106 +type testIPv4UnicastConn interface {
107 + TOS() (int, error)
108 + SetTOS(int) error
109 + TTL() (int, error)
110 + SetTTL(int) error
111 +}
112 +
113 +func testUnicastSocketOptions(t *testing.T, c testIPv4UnicastConn) {
114 + tos := iana.DiffServCS0 | iana.NotECNTransport
115 + switch runtime.GOOS {
116 + case "windows":
117 + // IP_TOS option is supported on Windows 8 and beyond.
118 + t.Skipf("skipping IP_TOS test on %q", runtime.GOOS)
119 + }
120 +
121 + if err := c.SetTOS(tos); err != nil {
122 + t.Fatalf("ipv4.Conn.SetTOS failed: %v", err)
123 + }
124 + if v, err := c.TOS(); err != nil {
125 + t.Fatalf("ipv4.Conn.TOS failed: %v", err)
126 + } else if v != tos {
127 + t.Fatalf("got unexpected TOS value %v; expected %v", v, tos)
128 + }
129 + const ttl = 255
130 + if err := c.SetTTL(ttl); err != nil {
131 + t.Fatalf("ipv4.Conn.SetTTL failed: %v", err)
132 + }
133 + if v, err := c.TTL(); err != nil {
134 + t.Fatalf("ipv4.Conn.TTL failed: %v", err)
135 + } else if v != ttl {
136 + t.Fatalf("got unexpected TTL value %v; expected %v", v, ttl)
137 + }
138 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_darwin.go new
+62
@@ -0,0 +1,62 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_darwin.go
3 +
4 +package ipv4
5 +
6 +const (
7 + sysIP_OPTIONS = 0x1
8 + sysIP_HDRINCL = 0x2
9 + sysIP_TOS = 0x3
10 + sysIP_TTL = 0x4
11 + sysIP_RECVOPTS = 0x5
12 + sysIP_RECVRETOPTS = 0x6
13 + sysIP_RECVDSTADDR = 0x7
14 + sysIP_RETOPTS = 0x8
15 + sysIP_RECVIF = 0x14
16 + sysIP_STRIPHDR = 0x17
17 + sysIP_RECVTTL = 0x18
18 + sysIP_BOUND_IF = 0x19
19 + sysIP_PKTINFO = 0x1a
20 + sysIP_RECVPKTINFO = 0x1a
21 +
22 + sysIP_MULTICAST_IF = 0x9
23 + sysIP_MULTICAST_TTL = 0xa
24 + sysIP_MULTICAST_LOOP = 0xb
25 + sysIP_ADD_MEMBERSHIP = 0xc
26 + sysIP_DROP_MEMBERSHIP = 0xd
27 + sysIP_MULTICAST_VIF = 0xe
28 + sysIP_MULTICAST_IFINDEX = 0x42
29 + sysIP_ADD_SOURCE_MEMBERSHIP = 0x46
30 + sysIP_DROP_SOURCE_MEMBERSHIP = 0x47
31 + sysIP_BLOCK_SOURCE = 0x48
32 + sysIP_UNBLOCK_SOURCE = 0x49
33 +
34 + sysSizeofInetPktinfo = 0xc
35 +
36 + sysSizeofIPMreq = 0x8
37 + sysSizeofIPMreqn = 0xc
38 + sysSizeofIPMreqSource = 0xc
39 +)
40 +
41 +type sysInetPktinfo struct {
42 + Ifindex uint32
43 + Spec_dst [4]byte /* in_addr */
44 + Addr [4]byte /* in_addr */
45 +}
46 +
47 +type sysIPMreq struct {
48 + Multiaddr [4]byte /* in_addr */
49 + Interface [4]byte /* in_addr */
50 +}
51 +
52 +type sysIPMreqn struct {
53 + Multiaddr [4]byte /* in_addr */
54 + Address [4]byte /* in_addr */
55 + Ifindex int32
56 +}
57 +
58 +type sysIPMreqSource struct {
59 + Multiaddr [4]byte /* in_addr */
60 + Sourceaddr [4]byte /* in_addr */
61 + Interface [4]byte /* in_addr */
62 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_dragonfly.go new
+33
@@ -0,0 +1,33 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_dragonfly.go
3 +
4 +// +build dragonfly
5 +
6 +package ipv4
7 +
8 +const (
9 + sysIP_OPTIONS = 0x1
10 + sysIP_HDRINCL = 0x2
11 + sysIP_TOS = 0x3
12 + sysIP_TTL = 0x4
13 + sysIP_RECVOPTS = 0x5
14 + sysIP_RECVRETOPTS = 0x6
15 + sysIP_RECVDSTADDR = 0x7
16 + sysIP_RETOPTS = 0x8
17 + sysIP_RECVIF = 0x14
18 + sysIP_RECVTTL = 0x41
19 +
20 + sysIP_MULTICAST_IF = 0x9
21 + sysIP_MULTICAST_TTL = 0xa
22 + sysIP_MULTICAST_LOOP = 0xb
23 + sysIP_MULTICAST_VIF = 0xe
24 + sysIP_ADD_MEMBERSHIP = 0xc
25 + sysIP_DROP_MEMBERSHIP = 0xd
26 +
27 + sysSizeofIPMreq = 0x8
28 +)
29 +
30 +type sysIPMreq struct {
31 + Multiaddr [4]byte /* in_addr */
32 + Interface [4]byte /* in_addr */
33 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_freebsd.go new
+55
@@ -0,0 +1,55 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_freebsd.go
3 +
4 +package ipv4
5 +
6 +const (
7 + sysIP_OPTIONS = 0x1
8 + sysIP_HDRINCL = 0x2
9 + sysIP_TOS = 0x3
10 + sysIP_TTL = 0x4
11 + sysIP_RECVOPTS = 0x5
12 + sysIP_RECVRETOPTS = 0x6
13 + sysIP_RECVDSTADDR = 0x7
14 + sysIP_SENDSRCADDR = 0x7
15 + sysIP_RETOPTS = 0x8
16 + sysIP_RECVIF = 0x14
17 + sysIP_ONESBCAST = 0x17
18 + sysIP_BINDANY = 0x18
19 + sysIP_RECVTTL = 0x41
20 + sysIP_MINTTL = 0x42
21 + sysIP_DONTFRAG = 0x43
22 + sysIP_RECVTOS = 0x44
23 +
24 + sysIP_MULTICAST_IF = 0x9
25 + sysIP_MULTICAST_TTL = 0xa
26 + sysIP_MULTICAST_LOOP = 0xb
27 + sysIP_ADD_MEMBERSHIP = 0xc
28 + sysIP_DROP_MEMBERSHIP = 0xd
29 + sysIP_MULTICAST_VIF = 0xe
30 + sysIP_ADD_SOURCE_MEMBERSHIP = 0x46
31 + sysIP_DROP_SOURCE_MEMBERSHIP = 0x47
32 + sysIP_BLOCK_SOURCE = 0x48
33 + sysIP_UNBLOCK_SOURCE = 0x49
34 +
35 + sysSizeofIPMreq = 0x8
36 + sysSizeofIPMreqn = 0xc
37 + sysSizeofIPMreqSource = 0xc
38 +)
39 +
40 +type sysIPMreq struct {
41 + Multiaddr [4]byte /* in_addr */
42 + Interface [4]byte /* in_addr */
43 +}
44 +
45 +type sysIPMreqn struct {
46 + Multiaddr [4]byte /* in_addr */
47 + Address [4]byte /* in_addr */
48 + Ifindex int32
49 +}
50 +
51 +type sysIPMreqSource struct {
52 + Multiaddr [4]byte /* in_addr */
53 + Sourceaddr [4]byte /* in_addr */
54 + Interface [4]byte /* in_addr */
55 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_linux.go new
+94
@@ -0,0 +1,94 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_linux.go
3 +
4 +package ipv4
5 +
6 +const (
7 + sysIP_TOS = 0x1
8 + sysIP_TTL = 0x2
9 + sysIP_HDRINCL = 0x3
10 + sysIP_OPTIONS = 0x4
11 + sysIP_ROUTER_ALERT = 0x5
12 + sysIP_RECVOPTS = 0x6
13 + sysIP_RETOPTS = 0x7
14 + sysIP_PKTINFO = 0x8
15 + sysIP_PKTOPTIONS = 0x9
16 + sysIP_MTU_DISCOVER = 0xa
17 + sysIP_RECVERR = 0xb
18 + sysIP_RECVTTL = 0xc
19 + sysIP_RECVTOS = 0xd
20 + sysIP_MTU = 0xe
21 + sysIP_FREEBIND = 0xf
22 + sysIP_TRANSPARENT = 0x13
23 + sysIP_RECVRETOPTS = 0x7
24 + sysIP_ORIGDSTADDR = 0x14
25 + sysIP_RECVORIGDSTADDR = 0x14
26 + sysIP_MINTTL = 0x15
27 + sysIP_NODEFRAG = 0x16
28 + sysIP_UNICAST_IF = 0x32
29 +
30 + sysIP_MULTICAST_IF = 0x20
31 + sysIP_MULTICAST_TTL = 0x21
32 + sysIP_MULTICAST_LOOP = 0x22
33 + sysIP_ADD_MEMBERSHIP = 0x23
34 + sysIP_DROP_MEMBERSHIP = 0x24
35 + sysIP_UNBLOCK_SOURCE = 0x25
36 + sysIP_BLOCK_SOURCE = 0x26
37 + sysIP_ADD_SOURCE_MEMBERSHIP = 0x27
38 + sysIP_DROP_SOURCE_MEMBERSHIP = 0x28
39 + sysIP_MULTICAST_ALL = 0x31
40 +
41 + sysIP_PMTUDISC_DONT = 0x0
42 + sysIP_PMTUDISC_WANT = 0x1
43 + sysIP_PMTUDISC_DO = 0x2
44 + sysIP_PMTUDISC_PROBE = 0x3
45 + sysIP_PMTUDISC_INTERFACE = 0x4
46 + sysIP_PMTUDISC_OMIT = 0x5
47 +
48 + sysSO_EE_ORIGIN_NONE = 0x0
49 + sysSO_EE_ORIGIN_LOCAL = 0x1
50 + sysSO_EE_ORIGIN_ICMP = 0x2
51 + sysSO_EE_ORIGIN_ICMP6 = 0x3
52 + sysSO_EE_ORIGIN_TXSTATUS = 0x4
53 + sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
54 +
55 + sysSizeofInetPktinfo = 0xc
56 + sysSizeofSockExtendedErr = 0x10
57 +
58 + sysSizeofIPMreq = 0x8
59 + sysSizeofIPMreqn = 0xc
60 + sysSizeofIPMreqSource = 0xc
61 +)
62 +
63 +type sysInetPktinfo struct {
64 + Ifindex int32
65 + Spec_dst [4]byte /* in_addr */
66 + Addr [4]byte /* in_addr */
67 +}
68 +
69 +type sysSockExtendedErr struct {
70 + Errno uint32
71 + Origin uint8
72 + Type uint8
73 + Code uint8
74 + Pad uint8
75 + Info uint32
76 + Data uint32
77 +}
78 +
79 +type sysIPMreq struct {
80 + Multiaddr [4]byte /* in_addr */
81 + Interface [4]byte /* in_addr */
82 +}
83 +
84 +type sysIPMreqn struct {
85 + Multiaddr [4]byte /* in_addr */
86 + Address [4]byte /* in_addr */
87 + Ifindex int32
88 +}
89 +
90 +type sysIPMreqSource struct {
91 + Multiaddr uint32
92 + Interface uint32
93 + Sourceaddr uint32
94 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_netbsd.go new
+30
@@ -0,0 +1,30 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_netbsd.go
3 +
4 +package ipv4
5 +
6 +const (
7 + sysIP_OPTIONS = 0x1
8 + sysIP_HDRINCL = 0x2
9 + sysIP_TOS = 0x3
10 + sysIP_TTL = 0x4
11 + sysIP_RECVOPTS = 0x5
12 + sysIP_RECVRETOPTS = 0x6
13 + sysIP_RECVDSTADDR = 0x7
14 + sysIP_RETOPTS = 0x8
15 + sysIP_RECVIF = 0x14
16 + sysIP_RECVTTL = 0x17
17 +
18 + sysIP_MULTICAST_IF = 0x9
19 + sysIP_MULTICAST_TTL = 0xa
20 + sysIP_MULTICAST_LOOP = 0xb
21 + sysIP_ADD_MEMBERSHIP = 0xc
22 + sysIP_DROP_MEMBERSHIP = 0xd
23 +
24 + sysSizeofIPMreq = 0x8
25 +)
26 +
27 +type sysIPMreq struct {
28 + Multiaddr [4]byte /* in_addr */
29 + Interface [4]byte /* in_addr */
30 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_openbsd.go new
+30
@@ -0,0 +1,30 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_openbsd.go
3 +
4 +package ipv4
5 +
6 +const (
7 + sysIP_OPTIONS = 0x1
8 + sysIP_HDRINCL = 0x2
9 + sysIP_TOS = 0x3
10 + sysIP_TTL = 0x4
11 + sysIP_RECVOPTS = 0x5
12 + sysIP_RECVRETOPTS = 0x6
13 + sysIP_RECVDSTADDR = 0x7
14 + sysIP_RETOPTS = 0x8
15 + sysIP_RECVIF = 0x1e
16 + sysIP_RECVTTL = 0x1f
17 +
18 + sysIP_MULTICAST_IF = 0x9
19 + sysIP_MULTICAST_TTL = 0xa
20 + sysIP_MULTICAST_LOOP = 0xb
21 + sysIP_ADD_MEMBERSHIP = 0xc
22 + sysIP_DROP_MEMBERSHIP = 0xd
23 +
24 + sysSizeofIPMreq = 0x8
25 +)
26 +
27 +type sysIPMreq struct {
28 + Multiaddr [4]byte /* in_addr */
29 + Interface [4]byte /* in_addr */
30 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4/zsys_solaris.go new
+60
@@ -0,0 +1,60 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_solaris.go
3 +
4 +// +build solaris
5 +
6 +package ipv4
7 +
8 +const (
9 + sysIP_OPTIONS = 0x1
10 + sysIP_HDRINCL = 0x2
11 + sysIP_TOS = 0x3
12 + sysIP_TTL = 0x4
13 + sysIP_RECVOPTS = 0x5
14 + sysIP_RECVRETOPTS = 0x6
15 + sysIP_RECVDSTADDR = 0x7
16 + sysIP_RETOPTS = 0x8
17 + sysIP_RECVIF = 0x9
18 + sysIP_RECVSLLA = 0xa
19 + sysIP_RECVTTL = 0xb
20 + sysIP_NEXTHOP = 0x19
21 + sysIP_PKTINFO = 0x1a
22 + sysIP_RECVPKTINFO = 0x1a
23 + sysIP_DONTFRAG = 0x1b
24 + sysIP_BOUND_IF = 0x41
25 + sysIP_UNSPEC_SRC = 0x42
26 + sysIP_BROADCAST_TTL = 0x43
27 + sysIP_DHCPINIT_IF = 0x45
28 +
29 + sysIP_MULTICAST_IF = 0x10
30 + sysIP_MULTICAST_TTL = 0x11
31 + sysIP_MULTICAST_LOOP = 0x12
32 + sysIP_ADD_MEMBERSHIP = 0x13
33 + sysIP_DROP_MEMBERSHIP = 0x14
34 + sysIP_BLOCK_SOURCE = 0x15
35 + sysIP_UNBLOCK_SOURCE = 0x16
36 + sysIP_ADD_SOURCE_MEMBERSHIP = 0x17
37 + sysIP_DROP_SOURCE_MEMBERSHIP = 0x18
38 +
39 + sysSizeofInetPktinfo = 0xc
40 +
41 + sysSizeofIPMreq = 0x8
42 + sysSizeofIPMreqSource = 0xc
43 +)
44 +
45 +type sysInetPktinfo struct {
46 + Ifindex uint32
47 + Spec_dst [4]byte /* in_addr */
48 + Addr [4]byte /* in_addr */
49 +}
50 +
51 +type sysIPMreq struct {
52 + Multiaddr [4]byte /* in_addr */
53 + Interface [4]byte /* in_addr */
54 +}
55 +
56 +type sysIPMreqSource struct {
57 + Multiaddr [4]byte /* in_addr */
58 + Sourceaddr [4]byte /* in_addr */
59 + Interface [4]byte /* in_addr */
60 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/control.go new
+83
@@ -0,0 +1,83 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "errors"
9 + "fmt"
10 + "net"
11 + "sync"
12 +)
13 +
14 +var (
15 + errMissingAddress = errors.New("missing address")
16 + errInvalidConnType = errors.New("invalid conn type")
17 + errNoSuchInterface = errors.New("no such interface")
18 +)
19 +
20 +// References:
21 +//
22 +// RFC 2292 Advanced Sockets API for IPv6
23 +// http://tools.ietf.org/html/rfc2292
24 +// RFC 2460 Internet Protocol, Version 6 (IPv6) Specification
25 +// http://tools.ietf.org/html/rfc2460
26 +// RFC 3493 Basic Socket Interface Extensions for IPv6
27 +// http://tools.ietf.org/html/rfc3493.html
28 +// RFC 3542 Advanced Sockets Application Program Interface (API) for IPv6
29 +// http://tools.ietf.org/html/rfc3542
30 +//
31 +// Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the
32 +// former still support RFC 2292 only. Please be aware that almost
33 +// all protocol implementations prohibit using a combination of RFC
34 +// 2292 and RFC 3542 for some practical reasons.
35 +
36 +type rawOpt struct {
37 + sync.Mutex
38 + cflags ControlFlags
39 +}
40 +
41 +func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
42 +func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
43 +func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
44 +
45 +// A ControlFlags represents per packet basis IP-level socket option
46 +// control flags.
47 +type ControlFlags uint
48 +
49 +const (
50 + FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet
51 + FlagHopLimit // pass the hop limit on the received packet
52 + FlagSrc // pass the source address on the received packet
53 + FlagDst // pass the destination address on the received packet
54 + FlagInterface // pass the interface index on the received packet
55 + FlagPathMTU // pass the path MTU on the received packet path
56 +)
57 +
58 +// A ControlMessage represents per packet basis IP-level socket
59 +// options.
60 +type ControlMessage struct {
61 + // Receiving socket options: SetControlMessage allows to
62 + // receive the options from the protocol stack using ReadFrom
63 + // method of PacketConn.
64 + //
65 + // Specifying socket options: ControlMessage for WriteTo
66 + // method of PacketConn allows to send the options to the
67 + // protocol stack.
68 + //
69 + TrafficClass int // traffic class, must be 1 <= value <= 255 when specifying
70 + HopLimit int // hop limit, must be 1 <= value <= 255 when specifying
71 + Src net.IP // source address, specifying only
72 + Dst net.IP // destination address, receiving only
73 + IfIndex int // interface index, must be 1 <= value when specifying
74 + NextHop net.IP // next hop address, specifying only
75 + MTU int // path MTU, receiving only
76 +}
77 +
78 +func (cm *ControlMessage) String() string {
79 + if cm == nil {
80 + return "<nil>"
81 + }
82 + return fmt.Sprintf("tclass: %#x, hoplim: %v, src: %v, dst: %v, ifindex: %v, nexthop: %v, mtu: %v", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
83 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/control_rfc2292_unix.go new
+151
@@ -0,0 +1,151 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "os"
12 + "syscall"
13 + "unsafe"
14 +)
15 +
16 +const pktinfo = FlagDst | FlagInterface
17 +
18 +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
19 + opt.Lock()
20 + defer opt.Unlock()
21 + if cf&FlagHopLimit != 0 {
22 + if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
23 + return err
24 + }
25 + if on {
26 + opt.set(FlagHopLimit)
27 + } else {
28 + opt.clear(FlagHopLimit)
29 + }
30 + }
31 + if cf&pktinfo != 0 {
32 + if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
33 + return err
34 + }
35 + if on {
36 + opt.set(cf & pktinfo)
37 + } else {
38 + opt.clear(cf & pktinfo)
39 + }
40 + }
41 + return nil
42 +}
43 +
44 +func newControlMessage(opt *rawOpt) (oob []byte) {
45 + opt.Lock()
46 + defer opt.Unlock()
47 + l, off := 0, 0
48 + if opt.isset(FlagHopLimit) {
49 + l += syscall.CmsgSpace(4)
50 + }
51 + if opt.isset(pktinfo) {
52 + l += syscall.CmsgSpace(sysSizeofPacketInfo)
53 + }
54 + if l > 0 {
55 + oob = make([]byte, l)
56 + if opt.isset(FlagHopLimit) {
57 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
58 + m.Level = ianaProtocolIPv6
59 + m.Type = sysSockopt2292HopLimit
60 + m.SetLen(syscall.CmsgLen(4))
61 + off += syscall.CmsgSpace(4)
62 + }
63 + if opt.isset(pktinfo) {
64 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
65 + m.Level = ianaProtocolIPv6
66 + m.Type = sysSockopt2292PacketInfo
67 + m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
68 + off += syscall.CmsgSpace(sysSizeofPacketInfo)
69 + }
70 + }
71 + return
72 +}
73 +
74 +func parseControlMessage(b []byte) (*ControlMessage, error) {
75 + if len(b) == 0 {
76 + return nil, nil
77 + }
78 + cmsgs, err := syscall.ParseSocketControlMessage(b)
79 + if err != nil {
80 + return nil, os.NewSyscallError("parse socket control message", err)
81 + }
82 + cm := &ControlMessage{}
83 + for _, m := range cmsgs {
84 + if m.Header.Level != ianaProtocolIPv6 {
85 + continue
86 + }
87 + switch m.Header.Type {
88 + case sysSockopt2292HopLimit:
89 + cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
90 + case sysSockopt2292PacketInfo:
91 + pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
92 + cm.IfIndex = int(pi.IfIndex)
93 + cm.Dst = pi.IP[:]
94 + }
95 + }
96 + return cm, nil
97 +}
98 +
99 +func marshalControlMessage(cm *ControlMessage) (oob []byte) {
100 + if cm == nil {
101 + return
102 + }
103 + l, off := 0, 0
104 + if cm.HopLimit > 0 {
105 + l += syscall.CmsgSpace(4)
106 + }
107 + pion := false
108 + if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
109 + pion = true
110 + l += syscall.CmsgSpace(sysSizeofPacketInfo)
111 + }
112 + if len(cm.NextHop) == net.IPv6len {
113 + l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
114 + }
115 + if l > 0 {
116 + oob = make([]byte, l)
117 + if cm.HopLimit > 0 {
118 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
119 + m.Level = ianaProtocolIPv6
120 + m.Type = sysSockopt2292HopLimit
121 + m.SetLen(syscall.CmsgLen(4))
122 + data := oob[off+syscall.CmsgLen(0):]
123 + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
124 + off += syscall.CmsgSpace(4)
125 + }
126 + if pion {
127 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
128 + m.Level = ianaProtocolIPv6
129 + m.Type = sysSockopt2292PacketInfo
130 + m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
131 + pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
132 + if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
133 + copy(pi.IP[:], ip)
134 + }
135 + if cm.IfIndex != 0 {
136 + pi.IfIndex = uint32(cm.IfIndex)
137 + }
138 + off += syscall.CmsgSpace(sysSizeofPacketInfo)
139 + }
140 + if len(cm.NextHop) == net.IPv6len {
141 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
142 + m.Level = ianaProtocolIPv6
143 + m.Type = sysSockopt2292NextHop
144 + m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
145 + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
146 + setSockaddr(sa, cm.NextHop, cm.IfIndex)
147 + off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
148 + }
149 + }
150 + return
151 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/control_rfc3542_stub.go new
+27
@@ -0,0 +1,27 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv6
8 +
9 +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
10 + // TODO(mikio): Implement this
11 + return errOpNoSupport
12 +}
13 +
14 +func newControlMessage(opt *rawOpt) (oob []byte) {
15 + // TODO(mikio): Implement this
16 + return nil
17 +}
18 +
19 +func parseControlMessage(b []byte) (*ControlMessage, error) {
20 + // TODO(mikio): Implement this
21 + return nil, errOpNoSupport
22 +}
23 +
24 +func marshalControlMessage(cm *ControlMessage) (oob []byte) {
25 + // TODO(mikio): Implement this
26 + return nil
27 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/control_rfc3542_unix.go new
+210
@@ -0,0 +1,210 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "os"
12 + "syscall"
13 + "unsafe"
14 +)
15 +
16 +const pktinfo = FlagDst | FlagInterface
17 +
18 +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
19 + opt.Lock()
20 + defer opt.Unlock()
21 + if cf&FlagTrafficClass != 0 {
22 + if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
23 + return err
24 + }
25 + if on {
26 + opt.set(FlagTrafficClass)
27 + } else {
28 + opt.clear(FlagTrafficClass)
29 + }
30 + }
31 + if cf&FlagHopLimit != 0 {
32 + if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
33 + return err
34 + }
35 + if on {
36 + opt.set(FlagHopLimit)
37 + } else {
38 + opt.clear(FlagHopLimit)
39 + }
40 + }
41 + if cf&pktinfo != 0 {
42 + if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
43 + return err
44 + }
45 + if on {
46 + opt.set(cf & pktinfo)
47 + } else {
48 + opt.clear(cf & pktinfo)
49 + }
50 + }
51 + if cf&FlagPathMTU != 0 {
52 + if err := setIPv6ReceivePathMTU(fd, on); err != nil {
53 + return err
54 + }
55 + if on {
56 + opt.set(FlagPathMTU)
57 + } else {
58 + opt.clear(FlagPathMTU)
59 + }
60 + }
61 + return nil
62 +}
63 +
64 +func newControlMessage(opt *rawOpt) (oob []byte) {
65 + opt.Lock()
66 + defer opt.Unlock()
67 + l, off := 0, 0
68 + if opt.isset(FlagTrafficClass) {
69 + l += syscall.CmsgSpace(4)
70 + }
71 + if opt.isset(FlagHopLimit) {
72 + l += syscall.CmsgSpace(4)
73 + }
74 + if opt.isset(pktinfo) {
75 + l += syscall.CmsgSpace(sysSizeofPacketInfo)
76 + }
77 + if opt.isset(FlagPathMTU) {
78 + l += syscall.CmsgSpace(sysSizeofMTUInfo)
79 + }
80 + if l > 0 {
81 + oob = make([]byte, l)
82 + if opt.isset(FlagTrafficClass) {
83 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
84 + m.Level = ianaProtocolIPv6
85 + m.Type = sysSockoptReceiveTrafficClass
86 + m.SetLen(syscall.CmsgLen(4))
87 + off += syscall.CmsgSpace(4)
88 + }
89 + if opt.isset(FlagHopLimit) {
90 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
91 + m.Level = ianaProtocolIPv6
92 + m.Type = sysSockoptReceiveHopLimit
93 + m.SetLen(syscall.CmsgLen(4))
94 + off += syscall.CmsgSpace(4)
95 + }
96 + if opt.isset(pktinfo) {
97 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
98 + m.Level = ianaProtocolIPv6
99 + m.Type = sysSockoptReceivePacketInfo
100 + m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
101 + off += syscall.CmsgSpace(sysSizeofPacketInfo)
102 + }
103 + if opt.isset(FlagPathMTU) {
104 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
105 + m.Level = ianaProtocolIPv6
106 + m.Type = sysSockoptReceivePathMTU
107 + m.SetLen(syscall.CmsgLen(sysSizeofMTUInfo))
108 + off += syscall.CmsgSpace(sysSizeofMTUInfo)
109 + }
110 + }
111 + return
112 +}
113 +
114 +func parseControlMessage(b []byte) (*ControlMessage, error) {
115 + if len(b) == 0 {
116 + return nil, nil
117 + }
118 + cmsgs, err := syscall.ParseSocketControlMessage(b)
119 + if err != nil {
120 + return nil, os.NewSyscallError("parse socket control message", err)
121 + }
122 + cm := &ControlMessage{}
123 + for _, m := range cmsgs {
124 + if m.Header.Level != ianaProtocolIPv6 {
125 + continue
126 + }
127 + switch m.Header.Type {
128 + case sysSockoptTrafficClass:
129 + cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
130 + case sysSockoptHopLimit:
131 + cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
132 + case sysSockoptPacketInfo:
133 + pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
134 + cm.Dst = pi.IP[:]
135 + cm.IfIndex = int(pi.IfIndex)
136 + case sysSockoptPathMTU:
137 + mi := (*sysMTUInfo)(unsafe.Pointer(&m.Data[0]))
138 + cm.Dst = mi.Addr.Addr[:]
139 + cm.IfIndex = int(mi.Addr.Scope_id)
140 + cm.MTU = int(mi.MTU)
141 + }
142 + }
143 + return cm, nil
144 +}
145 +
146 +func marshalControlMessage(cm *ControlMessage) (oob []byte) {
147 + if cm == nil {
148 + return
149 + }
150 + l, off := 0, 0
151 + if cm.TrafficClass > 0 {
152 + l += syscall.CmsgSpace(4)
153 + }
154 + if cm.HopLimit > 0 {
155 + l += syscall.CmsgSpace(4)
156 + }
157 + pion := false
158 + if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
159 + pion = true
160 + l += syscall.CmsgSpace(sysSizeofPacketInfo)
161 + }
162 + if len(cm.NextHop) == net.IPv6len {
163 + l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
164 + }
165 + if l > 0 {
166 + oob = make([]byte, l)
167 + if cm.TrafficClass > 0 {
168 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
169 + m.Level = ianaProtocolIPv6
170 + m.Type = sysSockoptTrafficClass
171 + m.SetLen(syscall.CmsgLen(4))
172 + data := oob[off+syscall.CmsgLen(0):]
173 + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
174 + off += syscall.CmsgSpace(4)
175 + }
176 + if cm.HopLimit > 0 {
177 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
178 + m.Level = ianaProtocolIPv6
179 + m.Type = sysSockoptHopLimit
180 + m.SetLen(syscall.CmsgLen(4))
181 + data := oob[off+syscall.CmsgLen(0):]
182 + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
183 + off += syscall.CmsgSpace(4)
184 + }
185 + if pion {
186 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
187 + m.Level = ianaProtocolIPv6
188 + m.Type = sysSockoptPacketInfo
189 + m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
190 + pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
191 + if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
192 + copy(pi.IP[:], ip)
193 + }
194 + if cm.IfIndex != 0 {
195 + pi.IfIndex = uint32(cm.IfIndex)
196 + }
197 + off += syscall.CmsgSpace(sysSizeofPacketInfo)
198 + }
199 + if len(cm.NextHop) == net.IPv6len {
200 + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
201 + m.Level = ianaProtocolIPv6
202 + m.Type = sysSockoptNextHop
203 + m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
204 + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
205 + setSockaddr(sa, cm.NextHop, cm.IfIndex)
206 + off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
207 + }
208 + }
209 + return
210 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/control_rfc3542_windows.go new
+27
@@ -0,0 +1,27 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import "syscall"
8 +
9 +func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error {
10 + // TODO(mikio): Implement this
11 + return syscall.EWINDOWS
12 +}
13 +
14 +func newControlMessage(opt *rawOpt) (oob []byte) {
15 + // TODO(mikio): Implement this
16 + return nil
17 +}
18 +
19 +func parseControlMessage(b []byte) (*ControlMessage, error) {
20 + // TODO(mikio): Implement this
21 + return nil, syscall.EWINDOWS
22 +}
23 +
24 +func marshalControlMessage(cm *ControlMessage) (oob []byte) {
25 + // TODO(mikio): Implement this
26 + return nil
27 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_darwin.go new
+95
@@ -0,0 +1,95 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#define __APPLE_USE_RFC_3542
13 +#include <netinet/in.h>
14 +#include <netinet/icmp6.h>
15 +*/
16 +import "C"
17 +
18 +const (
19 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
20 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
21 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
22 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
23 + sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP
24 + sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP
25 +
26 + sysIPV6_PORTRANGE = C.IPV6_PORTRANGE
27 + sysICMP6_FILTER = C.ICMP6_FILTER
28 + sysIPV6_2292PKTINFO = C.IPV6_2292PKTINFO
29 + sysIPV6_2292HOPLIMIT = C.IPV6_2292HOPLIMIT
30 + sysIPV6_2292NEXTHOP = C.IPV6_2292NEXTHOP
31 + sysIPV6_2292HOPOPTS = C.IPV6_2292HOPOPTS
32 + sysIPV6_2292DSTOPTS = C.IPV6_2292DSTOPTS
33 + sysIPV6_2292RTHDR = C.IPV6_2292RTHDR
34 +
35 + sysIPV6_2292PKTOPTIONS = C.IPV6_2292PKTOPTIONS
36 +
37 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
38 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
39 +
40 + sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY
41 +
42 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
43 + sysIPV6_TCLASS = C.IPV6_TCLASS
44 +
45 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
46 +
47 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
48 +
49 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
50 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
51 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
52 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
53 +
54 + sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU
55 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
56 +
57 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
58 +
59 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
60 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
61 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
62 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
63 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
64 + sysIPV6_RTHDR = C.IPV6_RTHDR
65 +
66 + sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL
67 +
68 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
69 +
70 + sysIPV6_PREFER_TEMPADDR = C.IPV6_PREFER_TEMPADDR
71 +
72 + sysIPV6_BOUND_IF = C.IPV6_BOUND_IF
73 +
74 + sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT
75 + sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
76 + sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
77 +
78 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
79 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
80 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
81 +
82 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
83 +
84 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
85 +)
86 +
87 +type sysSockaddrInet6 C.struct_sockaddr_in6
88 +
89 +type sysInet6Pktinfo C.struct_in6_pktinfo
90 +
91 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
92 +
93 +type sysIPv6Mreq C.struct_ipv6_mreq
94 +
95 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_dragonfly.go new
+84
@@ -0,0 +1,84 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#include <sys/param.h>
13 +#include <sys/socket.h>
14 +
15 +#include <netinet/in.h>
16 +#include <netinet/icmp6.h>
17 +*/
18 +import "C"
19 +
20 +const (
21 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
22 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
23 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
24 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
25 + sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP
26 + sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP
27 + sysIPV6_PORTRANGE = C.IPV6_PORTRANGE
28 + sysICMP6_FILTER = C.ICMP6_FILTER
29 +
30 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
31 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
32 +
33 + sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY
34 +
35 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
36 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
37 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
38 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
39 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
40 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
41 +
42 + sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU
43 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
44 +
45 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
46 +
47 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
48 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
49 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
50 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
51 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
52 + sysIPV6_RTHDR = C.IPV6_RTHDR
53 +
54 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
55 +
56 + sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL
57 +
58 + sysIPV6_TCLASS = C.IPV6_TCLASS
59 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
60 +
61 + sysIPV6_PREFER_TEMPADDR = C.IPV6_PREFER_TEMPADDR
62 +
63 + sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT
64 + sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
65 + sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
66 +
67 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
68 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
69 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
70 +
71 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
72 +
73 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
74 +)
75 +
76 +type sysSockaddrInet6 C.struct_sockaddr_in6
77 +
78 +type sysInet6Pktinfo C.struct_in6_pktinfo
79 +
80 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
81 +
82 +type sysIPv6Mreq C.struct_ipv6_mreq
83 +
84 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_freebsd.go new
+87
@@ -0,0 +1,87 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#include <sys/param.h>
13 +#include <sys/socket.h>
14 +
15 +#include <netinet/in.h>
16 +#include <netinet/icmp6.h>
17 +*/
18 +import "C"
19 +
20 +const (
21 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
22 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
23 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
24 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
25 + sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP
26 + sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP
27 + sysIPV6_PORTRANGE = C.IPV6_PORTRANGE
28 + sysICMP6_FILTER = C.ICMP6_FILTER
29 +
30 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
31 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
32 +
33 + sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY
34 +
35 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
36 +
37 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
38 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
39 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
40 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
41 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
42 +
43 + sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU
44 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
45 +
46 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
47 +
48 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
49 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
50 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
51 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
52 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
53 + sysIPV6_RTHDR = C.IPV6_RTHDR
54 +
55 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
56 +
57 + sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL
58 +
59 + sysIPV6_TCLASS = C.IPV6_TCLASS
60 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
61 +
62 + sysIPV6_PREFER_TEMPADDR = C.IPV6_PREFER_TEMPADDR
63 +
64 + sysIPV6_BINDANY = C.IPV6_BINDANY
65 +
66 + sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT
67 + sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
68 + sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
69 +
70 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
71 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
72 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
73 +
74 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
75 +
76 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
77 +)
78 +
79 +type sysSockaddrInet6 C.struct_sockaddr_in6
80 +
81 +type sysInet6Pktinfo C.struct_in6_pktinfo
82 +
83 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
84 +
85 +type sysIPv6Mreq C.struct_ipv6_mreq
86 +
87 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_linux.go new
+119
@@ -0,0 +1,119 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#include <linux/in6.h>
13 +#include <linux/ipv6.h>
14 +#include <linux/icmpv6.h>
15 +*/
16 +import "C"
17 +
18 +const (
19 + sysIPV6_ADDRFORM = C.IPV6_ADDRFORM
20 + sysIPV6_2292PKTINFO = C.IPV6_2292PKTINFO
21 + sysIPV6_2292HOPOPTS = C.IPV6_2292HOPOPTS
22 + sysIPV6_2292DSTOPTS = C.IPV6_2292DSTOPTS
23 + sysIPV6_2292RTHDR = C.IPV6_2292RTHDR
24 + sysIPV6_2292PKTOPTIONS = C.IPV6_2292PKTOPTIONS
25 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
26 + sysIPV6_2292HOPLIMIT = C.IPV6_2292HOPLIMIT
27 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
28 + sysIPV6_FLOWINFO = C.IPV6_FLOWINFO
29 +
30 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
31 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
32 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
33 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
34 + sysIPV6_ADD_MEMBERSHIP = C.IPV6_ADD_MEMBERSHIP
35 + sysIPV6_DROP_MEMBERSHIP = C.IPV6_DROP_MEMBERSHIP
36 + sysIPV6_ROUTER_ALERT = C.IPV6_ROUTER_ALERT
37 + sysIPV6_MTU_DISCOVER = C.IPV6_MTU_DISCOVER
38 + sysIPV6_MTU = C.IPV6_MTU
39 + sysIPV6_RECVERR = C.IPV6_RECVERR
40 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
41 + sysIPV6_JOIN_ANYCAST = C.IPV6_JOIN_ANYCAST
42 + sysIPV6_LEAVE_ANYCAST = C.IPV6_LEAVE_ANYCAST
43 +
44 + sysIPV6_PMTUDISC_DONT = C.IPV6_PMTUDISC_DONT
45 + sysIPV6_PMTUDISC_WANT = C.IPV6_PMTUDISC_WANT
46 + sysIPV6_PMTUDISC_DO = C.IPV6_PMTUDISC_DO
47 + sysIPV6_PMTUDISC_PROBE = C.IPV6_PMTUDISC_PROBE
48 + sysIPV6_PMTUDISC_INTERFACE = C.IPV6_PMTUDISC_INTERFACE
49 + sysIPV6_PMTUDISC_OMIT = C.IPV6_PMTUDISC_OMIT
50 +
51 + sysIPV6_FLOWLABEL_MGR = C.IPV6_FLOWLABEL_MGR
52 + sysIPV6_FLOWINFO_SEND = C.IPV6_FLOWINFO_SEND
53 +
54 + sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY
55 + sysIPV6_XFRM_POLICY = C.IPV6_XFRM_POLICY
56 +
57 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
58 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
59 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
60 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
61 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
62 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
63 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
64 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
65 + sysIPV6_RTHDR = C.IPV6_RTHDR
66 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
67 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
68 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
69 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
70 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
71 +
72 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
73 + sysIPV6_TCLASS = C.IPV6_TCLASS
74 +
75 + sysIPV6_ADDR_PREFERENCES = C.IPV6_ADDR_PREFERENCES
76 +
77 + sysIPV6_PREFER_SRC_TMP = C.IPV6_PREFER_SRC_TMP
78 + sysIPV6_PREFER_SRC_PUBLIC = C.IPV6_PREFER_SRC_PUBLIC
79 + sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = C.IPV6_PREFER_SRC_PUBTMP_DEFAULT
80 + sysIPV6_PREFER_SRC_COA = C.IPV6_PREFER_SRC_COA
81 + sysIPV6_PREFER_SRC_HOME = C.IPV6_PREFER_SRC_HOME
82 + sysIPV6_PREFER_SRC_CGA = C.IPV6_PREFER_SRC_CGA
83 + sysIPV6_PREFER_SRC_NONCGA = C.IPV6_PREFER_SRC_NONCGA
84 +
85 + sysIPV6_MINHOPCOUNT = C.IPV6_MINHOPCOUNT
86 +
87 + sysIPV6_ORIGDSTADDR = C.IPV6_ORIGDSTADDR
88 + sysIPV6_RECVORIGDSTADDR = C.IPV6_RECVORIGDSTADDR
89 + sysIPV6_TRANSPARENT = C.IPV6_TRANSPARENT
90 + sysIPV6_UNICAST_IF = C.IPV6_UNICAST_IF
91 +
92 + sysICMPV6_FILTER = C.ICMPV6_FILTER
93 +
94 + sysICMPV6_FILTER_BLOCK = C.ICMPV6_FILTER_BLOCK
95 + sysICMPV6_FILTER_PASS = C.ICMPV6_FILTER_PASS
96 + sysICMPV6_FILTER_BLOCKOTHERS = C.ICMPV6_FILTER_BLOCKOTHERS
97 + sysICMPV6_FILTER_PASSONLY = C.ICMPV6_FILTER_PASSONLY
98 +
99 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
100 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
101 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
102 + sysSizeofIPv6FlowlabelReq = C.sizeof_struct_in6_flowlabel_req
103 +
104 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
105 +
106 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
107 +)
108 +
109 +type sysSockaddrInet6 C.struct_sockaddr_in6
110 +
111 +type sysInet6Pktinfo C.struct_in6_pktinfo
112 +
113 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
114 +
115 +type sysIPv6FlowlabelReq C.struct_in6_flowlabel_req
116 +
117 +type sysIPv6Mreq C.struct_ipv6_mreq
118 +
119 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_netbsd.go new
+80
@@ -0,0 +1,80 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#include <sys/param.h>
13 +#include <sys/socket.h>
14 +
15 +#include <netinet/in.h>
16 +#include <netinet/icmp6.h>
17 +*/
18 +import "C"
19 +
20 +const (
21 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
22 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
23 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
24 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
25 + sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP
26 + sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP
27 + sysIPV6_PORTRANGE = C.IPV6_PORTRANGE
28 + sysICMP6_FILTER = C.ICMP6_FILTER
29 +
30 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
31 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
32 +
33 + sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY
34 +
35 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
36 +
37 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
38 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
39 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
40 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
41 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
42 +
43 + sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU
44 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
45 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
46 +
47 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
48 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
49 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
50 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
51 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
52 + sysIPV6_RTHDR = C.IPV6_RTHDR
53 +
54 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
55 +
56 + sysIPV6_TCLASS = C.IPV6_TCLASS
57 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
58 +
59 + sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT
60 + sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
61 + sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
62 +
63 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
64 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
65 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
66 +
67 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
68 +
69 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
70 +)
71 +
72 +type sysSockaddrInet6 C.struct_sockaddr_in6
73 +
74 +type sysInet6Pktinfo C.struct_in6_pktinfo
75 +
76 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
77 +
78 +type sysIPv6Mreq C.struct_ipv6_mreq
79 +
80 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_openbsd.go new
+89
@@ -0,0 +1,89 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#include <sys/param.h>
13 +#include <sys/socket.h>
14 +
15 +#include <netinet/in.h>
16 +#include <netinet/icmp6.h>
17 +*/
18 +import "C"
19 +
20 +const (
21 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
22 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
23 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
24 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
25 + sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP
26 + sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP
27 + sysIPV6_PORTRANGE = C.IPV6_PORTRANGE
28 + sysICMP6_FILTER = C.ICMP6_FILTER
29 +
30 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
31 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
32 +
33 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
34 +
35 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
36 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
37 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
38 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
39 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
40 +
41 + sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU
42 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
43 +
44 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
45 +
46 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
47 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
48 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
49 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
50 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
51 + sysIPV6_RTHDR = C.IPV6_RTHDR
52 +
53 + sysIPV6_AUTH_LEVEL = C.IPV6_AUTH_LEVEL
54 + sysIPV6_ESP_TRANS_LEVEL = C.IPV6_ESP_TRANS_LEVEL
55 + sysIPV6_ESP_NETWORK_LEVEL = C.IPV6_ESP_NETWORK_LEVEL
56 + sysIPSEC6_OUTSA = C.IPSEC6_OUTSA
57 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
58 +
59 + sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL
60 + sysIPV6_IPCOMP_LEVEL = C.IPV6_IPCOMP_LEVEL
61 +
62 + sysIPV6_TCLASS = C.IPV6_TCLASS
63 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
64 + sysIPV6_PIPEX = C.IPV6_PIPEX
65 +
66 + sysIPV6_RTABLE = C.IPV6_RTABLE
67 +
68 + sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT
69 + sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
70 + sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
71 +
72 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
73 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
74 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
75 +
76 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
77 +
78 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
79 +)
80 +
81 +type sysSockaddrInet6 C.struct_sockaddr_in6
82 +
83 +type sysInet6Pktinfo C.struct_in6_pktinfo
84 +
85 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
86 +
87 +type sysIPv6Mreq C.struct_ipv6_mreq
88 +
89 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/defs_solaris.go new
+96
@@ -0,0 +1,96 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// +godefs map struct_in6_addr [16]byte /* in6_addr */
8 +
9 +package ipv6
10 +
11 +/*
12 +#include <netinet/in.h>
13 +#include <netinet/icmp6.h>
14 +*/
15 +import "C"
16 +
17 +const (
18 + sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS
19 + sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF
20 + sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS
21 + sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP
22 + sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP
23 + sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP
24 +
25 + sysIPV6_PKTINFO = C.IPV6_PKTINFO
26 +
27 + sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT
28 + sysIPV6_NEXTHOP = C.IPV6_NEXTHOP
29 + sysIPV6_HOPOPTS = C.IPV6_HOPOPTS
30 + sysIPV6_DSTOPTS = C.IPV6_DSTOPTS
31 +
32 + sysIPV6_RTHDR = C.IPV6_RTHDR
33 + sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS
34 +
35 + sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO
36 + sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT
37 + sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS
38 +
39 + sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR
40 +
41 + sysIPV6_RECVRTHDRDSTOPTS = C.IPV6_RECVRTHDRDSTOPTS
42 +
43 + sysIPV6_CHECKSUM = C.IPV6_CHECKSUM
44 + sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS
45 + sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU
46 + sysIPV6_DONTFRAG = C.IPV6_DONTFRAG
47 + sysIPV6_SEC_OPT = C.IPV6_SEC_OPT
48 + sysIPV6_SRC_PREFERENCES = C.IPV6_SRC_PREFERENCES
49 + sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU
50 + sysIPV6_PATHMTU = C.IPV6_PATHMTU
51 + sysIPV6_TCLASS = C.IPV6_TCLASS
52 + sysIPV6_V6ONLY = C.IPV6_V6ONLY
53 +
54 + sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
55 +
56 + sysIPV6_PREFER_SRC_HOME = C.IPV6_PREFER_SRC_HOME
57 + sysIPV6_PREFER_SRC_COA = C.IPV6_PREFER_SRC_COA
58 + sysIPV6_PREFER_SRC_PUBLIC = C.IPV6_PREFER_SRC_PUBLIC
59 + sysIPV6_PREFER_SRC_TMP = C.IPV6_PREFER_SRC_TMP
60 + sysIPV6_PREFER_SRC_NONCGA = C.IPV6_PREFER_SRC_NONCGA
61 + sysIPV6_PREFER_SRC_CGA = C.IPV6_PREFER_SRC_CGA
62 +
63 + sysIPV6_PREFER_SRC_MIPMASK = C.IPV6_PREFER_SRC_MIPMASK
64 + sysIPV6_PREFER_SRC_MIPDEFAULT = C.IPV6_PREFER_SRC_MIPDEFAULT
65 + sysIPV6_PREFER_SRC_TMPMASK = C.IPV6_PREFER_SRC_TMPMASK
66 + sysIPV6_PREFER_SRC_TMPDEFAULT = C.IPV6_PREFER_SRC_TMPDEFAULT
67 + sysIPV6_PREFER_SRC_CGAMASK = C.IPV6_PREFER_SRC_CGAMASK
68 + sysIPV6_PREFER_SRC_CGADEFAULT = C.IPV6_PREFER_SRC_CGADEFAULT
69 +
70 + sysIPV6_PREFER_SRC_MASK = C.IPV6_PREFER_SRC_MASK
71 +
72 + sysIPV6_PREFER_SRC_DEFAULT = C.IPV6_PREFER_SRC_DEFAULT
73 +
74 + sysIPV6_BOUND_IF = C.IPV6_BOUND_IF
75 + sysIPV6_UNSPEC_SRC = C.IPV6_UNSPEC_SRC
76 +
77 + sysICMP6_FILTER = C.ICMP6_FILTER
78 +
79 + sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
80 + sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
81 + sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
82 +
83 + sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
84 +
85 + sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
86 +)
87 +
88 +type sysSockaddrInet6 C.struct_sockaddr_in6
89 +
90 +type sysInet6Pktinfo C.struct_in6_pktinfo
91 +
92 +type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
93 +
94 +type sysIPv6Mreq C.struct_ipv6_mreq
95 +
96 +type sysICMPv6Filter C.struct_icmp6_filter
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/dgramopt_posix.go new
+178
@@ -0,0 +1,178 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd windows
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// MulticastHopLimit returns the hop limit field value for outgoing
15 +// multicast packets.
16 +func (c *dgramOpt) MulticastHopLimit() (int, error) {
17 + if !c.ok() {
18 + return 0, syscall.EINVAL
19 + }
20 + fd, err := c.sysfd()
21 + if err != nil {
22 + return 0, err
23 + }
24 + return ipv6MulticastHopLimit(fd)
25 +}
26 +
27 +// SetMulticastHopLimit sets the hop limit field value for future
28 +// outgoing multicast packets.
29 +func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
30 + if !c.ok() {
31 + return syscall.EINVAL
32 + }
33 + fd, err := c.sysfd()
34 + if err != nil {
35 + return err
36 + }
37 + return setIPv6MulticastHopLimit(fd, hoplim)
38 +}
39 +
40 +// MulticastInterface returns the default interface for multicast
41 +// packet transmissions.
42 +func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
43 + if !c.ok() {
44 + return nil, syscall.EINVAL
45 + }
46 + fd, err := c.sysfd()
47 + if err != nil {
48 + return nil, err
49 + }
50 + return ipv6MulticastInterface(fd)
51 +}
52 +
53 +// SetMulticastInterface sets the default interface for future
54 +// multicast packet transmissions.
55 +func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
56 + if !c.ok() {
57 + return syscall.EINVAL
58 + }
59 + fd, err := c.sysfd()
60 + if err != nil {
61 + return err
62 + }
63 + return setIPv6MulticastInterface(fd, ifi)
64 +}
65 +
66 +// MulticastLoopback reports whether transmitted multicast packets
67 +// should be copied and send back to the originator.
68 +func (c *dgramOpt) MulticastLoopback() (bool, error) {
69 + if !c.ok() {
70 + return false, syscall.EINVAL
71 + }
72 + fd, err := c.sysfd()
73 + if err != nil {
74 + return false, err
75 + }
76 + return ipv6MulticastLoopback(fd)
77 +}
78 +
79 +// SetMulticastLoopback sets whether transmitted multicast packets
80 +// should be copied and send back to the originator.
81 +func (c *dgramOpt) SetMulticastLoopback(on bool) error {
82 + if !c.ok() {
83 + return syscall.EINVAL
84 + }
85 + fd, err := c.sysfd()
86 + if err != nil {
87 + return err
88 + }
89 + return setIPv6MulticastLoopback(fd, on)
90 +}
91 +
92 +// JoinGroup joins the group address group on the interface ifi.
93 +// It uses the system assigned multicast interface when ifi is nil,
94 +// although this is not recommended because the assignment depends on
95 +// platforms and sometimes it might require routing configuration.
96 +func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
97 + if !c.ok() {
98 + return syscall.EINVAL
99 + }
100 + fd, err := c.sysfd()
101 + if err != nil {
102 + return err
103 + }
104 + grp := netAddrToIP16(group)
105 + if grp == nil {
106 + return errMissingAddress
107 + }
108 + return joinIPv6Group(fd, ifi, grp)
109 +}
110 +
111 +// LeaveGroup leaves the group address group on the interface ifi.
112 +func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
113 + if !c.ok() {
114 + return syscall.EINVAL
115 + }
116 + fd, err := c.sysfd()
117 + if err != nil {
118 + return err
119 + }
120 + grp := netAddrToIP16(group)
121 + if grp == nil {
122 + return errMissingAddress
123 + }
124 + return leaveIPv6Group(fd, ifi, grp)
125 +}
126 +
127 +// Checksum reports whether the kernel will compute, store or verify a
128 +// checksum for both incoming and outgoing packets. If on is true, it
129 +// returns an offset in bytes into the data of where the checksum
130 +// field is located.
131 +func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
132 + if !c.ok() {
133 + return false, 0, syscall.EINVAL
134 + }
135 + fd, err := c.sysfd()
136 + if err != nil {
137 + return false, 0, err
138 + }
139 + return ipv6Checksum(fd)
140 +}
141 +
142 +// SetChecksum enables the kernel checksum processing. If on is ture,
143 +// the offset should be an offset in bytes into the data of where the
144 +// checksum field is located.
145 +func (c *dgramOpt) SetChecksum(on bool, offset int) error {
146 + if !c.ok() {
147 + return syscall.EINVAL
148 + }
149 + fd, err := c.sysfd()
150 + if err != nil {
151 + return err
152 + }
153 + return setIPv6Checksum(fd, on, offset)
154 +}
155 +
156 +// ICMPFilter returns an ICMP filter.
157 +func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
158 + if !c.ok() {
159 + return nil, syscall.EINVAL
160 + }
161 + fd, err := c.sysfd()
162 + if err != nil {
163 + return nil, err
164 + }
165 + return ipv6ICMPFilter(fd)
166 +}
167 +
168 +// SetICMPFilter deploys the ICMP filter.
169 +func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
170 + if !c.ok() {
171 + return syscall.EINVAL
172 + }
173 + fd, err := c.sysfd()
174 + if err != nil {
175 + return err
176 + }
177 + return setIPv6ICMPFilter(fd, f)
178 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/dgramopt_stub.go new
+95
@@ -0,0 +1,95 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv6
8 +
9 +import "net"
10 +
11 +// MulticastHopLimit returns the hop limit field value for outgoing
12 +// multicast packets.
13 +func (c *dgramOpt) MulticastHopLimit() (int, error) {
14 + // TODO(mikio): Implement this
15 + return 0, errOpNoSupport
16 +}
17 +
18 +// SetMulticastHopLimit sets the hop limit field value for future
19 +// outgoing multicast packets.
20 +func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
21 + // TODO(mikio): Implement this
22 + return errOpNoSupport
23 +}
24 +
25 +// MulticastInterface returns the default interface for multicast
26 +// packet transmissions.
27 +func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
28 + // TODO(mikio): Implement this
29 + return nil, errOpNoSupport
30 +}
31 +
32 +// SetMulticastInterface sets the default interface for future
33 +// multicast packet transmissions.
34 +func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
35 + // TODO(mikio): Implement this
36 + return errOpNoSupport
37 +}
38 +
39 +// MulticastLoopback reports whether transmitted multicast packets
40 +// should be copied and send back to the originator.
41 +func (c *dgramOpt) MulticastLoopback() (bool, error) {
42 + // TODO(mikio): Implement this
43 + return false, errOpNoSupport
44 +}
45 +
46 +// SetMulticastLoopback sets whether transmitted multicast packets
47 +// should be copied and send back to the originator.
48 +func (c *dgramOpt) SetMulticastLoopback(on bool) error {
49 + // TODO(mikio): Implement this
50 + return errOpNoSupport
51 +}
52 +
53 +// JoinGroup joins the group address group on the interface ifi.
54 +// It uses the system assigned multicast interface when ifi is nil,
55 +// although this is not recommended because the assignment depends on
56 +// platforms and sometimes it might require routing configuration.
57 +func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
58 + // TODO(mikio): Implement this
59 + return errOpNoSupport
60 +}
61 +
62 +// LeaveGroup leaves the group address group on the interface ifi.
63 +func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
64 + // TODO(mikio): Implement this
65 + return errOpNoSupport
66 +}
67 +
68 +// Checksum reports whether the kernel will compute, store or verify a
69 +// checksum for both incoming and outgoing packets. If on is true, it
70 +// returns an offset in bytes into the data of where the checksum
71 +// field is located.
72 +func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
73 + // TODO(mikio): Implement this
74 + return false, 0, errOpNoSupport
75 +}
76 +
77 +// SetChecksum enables the kernel checksum processing. If on is ture,
78 +// the offset should be an offset in bytes into the data of where the
79 +// checksum field is located.
80 +func (c *dgramOpt) SetChecksum(on bool, offset int) error {
81 + // TODO(mikio): Implement this
82 + return errOpNoSupport
83 +}
84 +
85 +// ICMPFilter returns an ICMP filter.
86 +func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
87 + // TODO(mikio): Implement this
88 + return nil, errOpNoSupport
89 +}
90 +
91 +// SetICMPFilter deploys the ICMP filter.
92 +func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
93 + // TODO(mikio): Implement this
94 + return errOpNoSupport
95 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/doc.go new
+193
@@ -0,0 +1,193 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// Package ipv6 implements IP-level socket options for the Internet
6 +// Protocol version 6.
7 +//
8 +// The package provides IP-level socket options that allow
9 +// manipulation of IPv6 facilities. The IPv6 and socket options for
10 +// IPv6 are defined in RFC 2460, RFC 3493 and RFC 3542.
11 +//
12 +//
13 +// Unicasting
14 +//
15 +// The options for unicasting are available for net.TCPConn,
16 +// net.UDPConn and net.IPConn which are created as network connections
17 +// that use the IPv6 transport. When a single TCP connection carrying
18 +// a data flow of multiple packets needs to indicate the flow is
19 +// important, ipv6.Conn is used to set the traffic class field on the
20 +// IPv6 header for each packet.
21 +//
22 +// ln, err := net.Listen("tcp6", "[::]:1024")
23 +// if err != nil {
24 +// // error handling
25 +// }
26 +// defer ln.Close()
27 +// for {
28 +// c, err := ln.Accept()
29 +// if err != nil {
30 +// // error handling
31 +// }
32 +// go func(c net.Conn) {
33 +// defer c.Close()
34 +//
35 +// The outgoing packets will be labeled DiffServ assured forwarding
36 +// class 1 low drop precedence, as known as AF11 packets.
37 +//
38 +// if err := ipv6.NewConn(c).SetTrafficClass(DiffServAF11); err != nil {
39 +// // error handling
40 +// }
41 +// if _, err := c.Write(data); err != nil {
42 +// // error handling
43 +// }
44 +// }(c)
45 +// }
46 +//
47 +//
48 +// Multicasting
49 +//
50 +// The options for multicasting are available for net.UDPConn and
51 +// net.IPconn which are created as network connections that use the
52 +// IPv6 transport. A few network facilities must be prepared before
53 +// you begin multicasting, at a minimum joining network interfaces and
54 +// multicast groups.
55 +//
56 +// en0, err := net.InterfaceByName("en0")
57 +// if err != nil {
58 +// // error handling
59 +// }
60 +// en1, err := net.InterfaceByIndex(911)
61 +// if err != nil {
62 +// // error handling
63 +// }
64 +// group := net.ParseIP("ff02::114")
65 +//
66 +// First, an application listens to an appropriate address with an
67 +// appropriate service port.
68 +//
69 +// c, err := net.ListenPacket("udp6", "[::]:1024")
70 +// if err != nil {
71 +// // error handling
72 +// }
73 +// defer c.Close()
74 +//
75 +// Second, the application joins multicast groups, starts listening to
76 +// the groups on the specified network interfaces. Note that the
77 +// service port for transport layer protocol does not matter with this
78 +// operation as joining groups affects only network and link layer
79 +// protocols, such as IPv6 and Ethernet.
80 +//
81 +// p := ipv6.NewPacketConn(c)
82 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil {
83 +// // error handling
84 +// }
85 +// if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil {
86 +// // error handling
87 +// }
88 +//
89 +// The application might set per packet control message transmissions
90 +// between the protocol stack within the kernel. When the application
91 +// needs a destination address on an incoming packet,
92 +// SetControlMessage of ipv6.PacketConn is used to enable control
93 +// message transmissons.
94 +//
95 +// if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil {
96 +// // error handling
97 +// }
98 +//
99 +// The application could identify whether the received packets are
100 +// of interest by using the control message that contains the
101 +// destination address of the received packet.
102 +//
103 +// b := make([]byte, 1500)
104 +// for {
105 +// n, rcm, src, err := p.ReadFrom(b)
106 +// if err != nil {
107 +// // error handling
108 +// }
109 +// if rcm.Dst.IsMulticast() {
110 +// if rcm.Dst.Equal(group)
111 +// // joined group, do something
112 +// } else {
113 +// // unknown group, discard
114 +// continue
115 +// }
116 +// }
117 +//
118 +// The application can also send both unicast and multicast packets.
119 +//
120 +// p.SetTrafficClass(DiffServCS0)
121 +// p.SetHopLimit(16)
122 +// if _, err := p.WriteTo(data[:n], nil, src); err != nil {
123 +// // error handling
124 +// }
125 +// dst := &net.UDPAddr{IP: group, Port: 1024}
126 +// wcm := ipv6.ControlMessage{TrafficClass: DiffServCS7, HopLimit: 1}
127 +// for _, ifi := range []*net.Interface{en0, en1} {
128 +// wcm.IfIndex = ifi.Index
129 +// if _, err := p.WriteTo(data[:n], &wcm, dst); err != nil {
130 +// // error handling
131 +// }
132 +// }
133 +// }
134 +//
135 +//
136 +// More multicasting
137 +//
138 +// An application that uses PacketConn may join multiple multicast
139 +// groups. For example, a UDP listener with port 1024 might join two
140 +// different groups across over two different network interfaces by
141 +// using:
142 +//
143 +// c, err := net.ListenPacket("udp6", "[::]:1024")
144 +// if err != nil {
145 +// // error handling
146 +// }
147 +// defer c.Close()
148 +// p := ipv6.NewPacketConn(c)
149 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}); err != nil {
150 +// // error handling
151 +// }
152 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
153 +// // error handling
154 +// }
155 +// if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
156 +// // error handling
157 +// }
158 +//
159 +// It is possible for multiple UDP listeners that listen on the same
160 +// UDP port to join the same multicast group. The net package will
161 +// provide a socket that listens to a wildcard address with reusable
162 +// UDP port when an appropriate multicast address prefix is passed to
163 +// the net.ListenPacket or net.ListenUDP.
164 +//
165 +// c1, err := net.ListenPacket("udp6", "[ff02::]:1024")
166 +// if err != nil {
167 +// // error handling
168 +// }
169 +// defer c1.Close()
170 +// c2, err := net.ListenPacket("udp6", "[ff02::]:1024")
171 +// if err != nil {
172 +// // error handling
173 +// }
174 +// defer c2.Close()
175 +// p1 := ipv6.NewPacketConn(c1)
176 +// if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
177 +// // error handling
178 +// }
179 +// p2 := ipv6.NewPacketConn(c2)
180 +// if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
181 +// // error handling
182 +// }
183 +//
184 +// Also it is possible for the application to leave or rejoin a
185 +// multicast group on the network interface.
186 +//
187 +// if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
188 +// // error handling
189 +// }
190 +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff01::114")}); err != nil {
191 +// // error handling
192 +// }
193 +package ipv6
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/endpoint.go new
+119
@@ -0,0 +1,119 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "net"
9 + "syscall"
10 + "time"
11 +)
12 +
13 +// A Conn represents a network endpoint that uses IPv6 transport.
14 +// It allows to set basic IP-level socket options such as traffic
15 +// class and hop limit.
16 +type Conn struct {
17 + genericOpt
18 +}
19 +
20 +type genericOpt struct {
21 + net.Conn
22 +}
23 +
24 +func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
25 +
26 +// PathMTU returns a path MTU value for the destination associated
27 +// with the endpoint.
28 +func (c *Conn) PathMTU() (int, error) {
29 + if !c.genericOpt.ok() {
30 + return 0, syscall.EINVAL
31 + }
32 + fd, err := c.genericOpt.sysfd()
33 + if err != nil {
34 + return 0, err
35 + }
36 + return ipv6PathMTU(fd)
37 +}
38 +
39 +// NewConn returns a new Conn.
40 +func NewConn(c net.Conn) *Conn {
41 + return &Conn{
42 + genericOpt: genericOpt{Conn: c},
43 + }
44 +}
45 +
46 +// A PacketConn represents a packet network endpoint that uses IPv6
47 +// transport. It is used to control several IP-level socket options
48 +// including IPv6 header manipulation. It also provides datagram
49 +// based network I/O methods specific to the IPv6 and higher layer
50 +// protocols such as OSPF, GRE, and UDP.
51 +type PacketConn struct {
52 + genericOpt
53 + dgramOpt
54 + payloadHandler
55 +}
56 +
57 +type dgramOpt struct {
58 + net.PacketConn
59 +}
60 +
61 +func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil }
62 +
63 +// SetControlMessage allows to receive the per packet basis IP-level
64 +// socket options.
65 +func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
66 + if !c.payloadHandler.ok() {
67 + return syscall.EINVAL
68 + }
69 + fd, err := c.payloadHandler.sysfd()
70 + if err != nil {
71 + return err
72 + }
73 + return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on)
74 +}
75 +
76 +// SetDeadline sets the read and write deadlines associated with the
77 +// endpoint.
78 +func (c *PacketConn) SetDeadline(t time.Time) error {
79 + if !c.payloadHandler.ok() {
80 + return syscall.EINVAL
81 + }
82 + return c.payloadHandler.SetDeadline(t)
83 +}
84 +
85 +// SetReadDeadline sets the read deadline associated with the
86 +// endpoint.
87 +func (c *PacketConn) SetReadDeadline(t time.Time) error {
88 + if !c.payloadHandler.ok() {
89 + return syscall.EINVAL
90 + }
91 + return c.payloadHandler.SetReadDeadline(t)
92 +}
93 +
94 +// SetWriteDeadline sets the write deadline associated with the
95 +// endpoint.
96 +func (c *PacketConn) SetWriteDeadline(t time.Time) error {
97 + if !c.payloadHandler.ok() {
98 + return syscall.EINVAL
99 + }
100 + return c.payloadHandler.SetWriteDeadline(t)
101 +}
102 +
103 +// Close closes the endpoint.
104 +func (c *PacketConn) Close() error {
105 + if !c.payloadHandler.ok() {
106 + return syscall.EINVAL
107 + }
108 + return c.payloadHandler.Close()
109 +}
110 +
111 +// NewPacketConn returns a new PacketConn using c as its underlying
112 +// transport.
113 +func NewPacketConn(c net.PacketConn) *PacketConn {
114 + return &PacketConn{
115 + genericOpt: genericOpt{Conn: c.(net.Conn)},
116 + dgramOpt: dgramOpt{PacketConn: c},
117 + payloadHandler: payloadHandler{PacketConn: c},
118 + }
119 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/gen.go new
+241
@@ -0,0 +1,241 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// This program generates internet protocol constants and tables by
8 +// reading IANA protocol registries.
9 +//
10 +// Usage:
11 +// go run gen.go > iana.go
12 +package main
13 +
14 +import (
15 + "bytes"
16 + "encoding/xml"
17 + "fmt"
18 + "go/format"
19 + "io"
20 + "net/http"
21 + "os"
22 + "strconv"
23 + "strings"
24 +)
25 +
26 +var registries = []struct {
27 + url string
28 + parse func(io.Writer, io.Reader) error
29 +}{
30 + {
31 + "http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml",
32 + parseICMPv6Parameters,
33 + },
34 + {
35 + "http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
36 + parseProtocolNumbers,
37 + },
38 +}
39 +
40 +func main() {
41 + var bb bytes.Buffer
42 + fmt.Fprintf(&bb, "// go run gen.go\n")
43 + fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
44 + fmt.Fprintf(&bb, "package ipv6\n\n")
45 + for _, r := range registries {
46 + resp, err := http.Get(r.url)
47 + if err != nil {
48 + fmt.Fprintln(os.Stderr, err)
49 + os.Exit(1)
50 + }
51 + defer resp.Body.Close()
52 + if resp.StatusCode != http.StatusOK {
53 + fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
54 + os.Exit(1)
55 + }
56 + if err := r.parse(&bb, resp.Body); err != nil {
57 + fmt.Fprintln(os.Stderr, err)
58 + os.Exit(1)
59 + }
60 + fmt.Fprintf(&bb, "\n")
61 + }
62 + b, err := format.Source(bb.Bytes())
63 + if err != nil {
64 + fmt.Fprintln(os.Stderr, err)
65 + os.Exit(1)
66 + }
67 + os.Stdout.Write(b)
68 +}
69 +
70 +func parseICMPv6Parameters(w io.Writer, r io.Reader) error {
71 + dec := xml.NewDecoder(r)
72 + var icp icmpv6Parameters
73 + if err := dec.Decode(&icp); err != nil {
74 + return err
75 + }
76 + prs := icp.escape()
77 + fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
78 + fmt.Fprintf(w, "const (\n")
79 + for _, pr := range prs {
80 + if pr.Name == "" {
81 + continue
82 + }
83 + fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Name, pr.Value)
84 + fmt.Fprintf(w, "// %s\n", pr.OrigName)
85 + }
86 + fmt.Fprintf(w, ")\n\n")
87 + fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
88 + fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n")
89 + for _, pr := range prs {
90 + if pr.Name == "" {
91 + continue
92 + }
93 + fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigName))
94 + }
95 + fmt.Fprintf(w, "}\n")
96 + return nil
97 +}
98 +
99 +type icmpv6Parameters struct {
100 + XMLName xml.Name `xml:"registry"`
101 + Title string `xml:"title"`
102 + Updated string `xml:"updated"`
103 + Registries []struct {
104 + Title string `xml:"title"`
105 + Records []struct {
106 + Value string `xml:"value"`
107 + Name string `xml:"name"`
108 + } `xml:"record"`
109 + } `xml:"registry"`
110 +}
111 +
112 +type canonICMPv6ParamRecord struct {
113 + OrigName string
114 + Name string
115 + Value int
116 +}
117 +
118 +func (icp *icmpv6Parameters) escape() []canonICMPv6ParamRecord {
119 + id := -1
120 + for i, r := range icp.Registries {
121 + if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") {
122 + id = i
123 + break
124 + }
125 + }
126 + if id < 0 {
127 + return nil
128 + }
129 + prs := make([]canonICMPv6ParamRecord, len(icp.Registries[id].Records))
130 + sr := strings.NewReplacer(
131 + "Messages", "",
132 + "Message", "",
133 + "ICMP", "",
134 + "+", "P",
135 + "-", "",
136 + "/", "",
137 + ".", "",
138 + " ", "",
139 + )
140 + for i, pr := range icp.Registries[id].Records {
141 + if strings.Contains(pr.Name, "Reserved") ||
142 + strings.Contains(pr.Name, "Unassigned") ||
143 + strings.Contains(pr.Name, "Deprecated") ||
144 + strings.Contains(pr.Name, "Experiment") ||
145 + strings.Contains(pr.Name, "experiment") {
146 + continue
147 + }
148 + ss := strings.Split(pr.Name, "\n")
149 + if len(ss) > 1 {
150 + prs[i].Name = strings.Join(ss, " ")
151 + } else {
152 + prs[i].Name = ss[0]
153 + }
154 + s := strings.TrimSpace(prs[i].Name)
155 + prs[i].OrigName = s
156 + prs[i].Name = sr.Replace(s)
157 + prs[i].Value, _ = strconv.Atoi(pr.Value)
158 + }
159 + return prs
160 +}
161 +
162 +func parseProtocolNumbers(w io.Writer, r io.Reader) error {
163 + dec := xml.NewDecoder(r)
164 + var pn protocolNumbers
165 + if err := dec.Decode(&pn); err != nil {
166 + return err
167 + }
168 + prs := pn.escape()
169 + fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated)
170 + fmt.Fprintf(w, "const (\n")
171 + for _, pr := range prs {
172 + if pr.Name == "" {
173 + continue
174 + }
175 + fmt.Fprintf(w, "ianaProtocol%s = %d", pr.Name, pr.Value)
176 + s := pr.Descr
177 + if s == "" {
178 + s = pr.OrigName
179 + }
180 + fmt.Fprintf(w, "// %s\n", s)
181 + }
182 + fmt.Fprintf(w, ")\n")
183 + return nil
184 +}
185 +
186 +type protocolNumbers struct {
187 + XMLName xml.Name `xml:"registry"`
188 + Title string `xml:"title"`
189 + Updated string `xml:"updated"`
190 + RegTitle string `xml:"registry>title"`
191 + Note string `xml:"registry>note"`
192 + Records []struct {
193 + Value string `xml:"value"`
194 + Name string `xml:"name"`
195 + Descr string `xml:"description"`
196 + } `xml:"registry>record"`
197 +}
198 +
199 +type canonProtocolRecord struct {
200 + OrigName string
201 + Name string
202 + Descr string
203 + Value int
204 +}
205 +
206 +func (pn *protocolNumbers) escape() []canonProtocolRecord {
207 + prs := make([]canonProtocolRecord, len(pn.Records))
208 + sr := strings.NewReplacer(
209 + "-in-", "in",
210 + "-within-", "within",
211 + "-over-", "over",
212 + "+", "P",
213 + "-", "",
214 + "/", "",
215 + ".", "",
216 + " ", "",
217 + )
218 + for i, pr := range pn.Records {
219 + prs[i].OrigName = pr.Name
220 + s := strings.TrimSpace(pr.Name)
221 + switch pr.Name {
222 + case "ISIS over IPv4":
223 + prs[i].Name = "ISIS"
224 + case "manet":
225 + prs[i].Name = "MANET"
226 + default:
227 + prs[i].Name = sr.Replace(s)
228 + }
229 + ss := strings.Split(pr.Descr, "\n")
230 + for i := range ss {
231 + ss[i] = strings.TrimSpace(ss[i])
232 + }
233 + if len(ss) > 1 {
234 + prs[i].Descr = strings.Join(ss, " ")
235 + } else {
236 + prs[i].Descr = ss[0]
237 + }
238 + prs[i].Value, _ = strconv.Atoi(pr.Value)
239 + }
240 + return prs
241 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/genericopt_posix.go new
+60
@@ -0,0 +1,60 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd windows
6 +
7 +package ipv6
8 +
9 +import "syscall"
10 +
11 +// TrafficClass returns the traffic class field value for outgoing
12 +// packets.
13 +func (c *genericOpt) TrafficClass() (int, error) {
14 + if !c.ok() {
15 + return 0, syscall.EINVAL
16 + }
17 + fd, err := c.sysfd()
18 + if err != nil {
19 + return 0, err
20 + }
21 + return ipv6TrafficClass(fd)
22 +}
23 +
24 +// SetTrafficClass sets the traffic class field value for future
25 +// outgoing packets.
26 +func (c *genericOpt) SetTrafficClass(tclass int) error {
27 + if !c.ok() {
28 + return syscall.EINVAL
29 + }
30 + fd, err := c.sysfd()
31 + if err != nil {
32 + return err
33 + }
34 + return setIPv6TrafficClass(fd, tclass)
35 +}
36 +
37 +// HopLimit returns the hop limit field value for outgoing packets.
38 +func (c *genericOpt) HopLimit() (int, error) {
39 + if !c.ok() {
40 + return 0, syscall.EINVAL
41 + }
42 + fd, err := c.sysfd()
43 + if err != nil {
44 + return 0, err
45 + }
46 + return ipv6HopLimit(fd)
47 +}
48 +
49 +// SetHopLimit sets the hop limit field value for future outgoing
50 +// packets.
51 +func (c *genericOpt) SetHopLimit(hoplim int) error {
52 + if !c.ok() {
53 + return syscall.EINVAL
54 + }
55 + fd, err := c.sysfd()
56 + if err != nil {
57 + return err
58 + }
59 + return setIPv6HopLimit(fd, hoplim)
60 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/genericopt_stub.go new
+34
@@ -0,0 +1,34 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv6
8 +
9 +// TrafficClass returns the traffic class field value for outgoing
10 +// packets.
11 +func (c *genericOpt) TrafficClass() (int, error) {
12 + // TODO(mikio): Implement this
13 + return 0, errOpNoSupport
14 +}
15 +
16 +// SetTrafficClass sets the traffic class field value for future
17 +// outgoing packets.
18 +func (c *genericOpt) SetTrafficClass(tclass int) error {
19 + // TODO(mikio): Implement this
20 + return errOpNoSupport
21 +}
22 +
23 +// HopLimit returns the hop limit field value for outgoing packets.
24 +func (c *genericOpt) HopLimit() (int, error) {
25 + // TODO(mikio): Implement this
26 + return 0, errOpNoSupport
27 +}
28 +
29 +// SetHopLimit sets the hop limit field value for future outgoing
30 +// packets.
31 +func (c *genericOpt) SetHopLimit(hoplim int) error {
32 + // TODO(mikio): Implement this
33 + return errOpNoSupport
34 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/gentest.go new
+195
@@ -0,0 +1,195 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build ignore
6 +
7 +// This program generates internet protocol constants by reading IANA
8 +// protocol registries.
9 +//
10 +// Usage:
11 +// go run gentest.go > iana_test.go
12 +package main
13 +
14 +import (
15 + "bytes"
16 + "encoding/xml"
17 + "fmt"
18 + "go/format"
19 + "io"
20 + "net/http"
21 + "os"
22 + "strconv"
23 + "strings"
24 +)
25 +
26 +var registries = []struct {
27 + url string
28 + parse func(io.Writer, io.Reader) error
29 +}{
30 + {
31 + "http://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
32 + parseDSCPRegistry,
33 + },
34 + {
35 + "http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
36 + parseTOSTCByte,
37 + },
38 +}
39 +
40 +func main() {
41 + var bb bytes.Buffer
42 + fmt.Fprintf(&bb, "// go run gentest.go\n")
43 + fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
44 + fmt.Fprintf(&bb, "package ipv6_test\n\n")
45 + for _, r := range registries {
46 + resp, err := http.Get(r.url)
47 + if err != nil {
48 + fmt.Fprintln(os.Stderr, err)
49 + os.Exit(1)
50 + }
51 + defer resp.Body.Close()
52 + if resp.StatusCode != http.StatusOK {
53 + fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
54 + os.Exit(1)
55 + }
56 + if err := r.parse(&bb, resp.Body); err != nil {
57 + fmt.Fprintln(os.Stderr, err)
58 + os.Exit(1)
59 + }
60 + fmt.Fprintf(&bb, "\n")
61 + }
62 + b, err := format.Source(bb.Bytes())
63 + if err != nil {
64 + fmt.Fprintln(os.Stderr, err)
65 + os.Exit(1)
66 + }
67 + os.Stdout.Write(b)
68 +}
69 +
70 +func parseDSCPRegistry(w io.Writer, r io.Reader) error {
71 + dec := xml.NewDecoder(r)
72 + var dr dscpRegistry
73 + if err := dec.Decode(&dr); err != nil {
74 + return err
75 + }
76 + drs := dr.escape()
77 + fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
78 + fmt.Fprintf(w, "const (\n")
79 + for _, dr := range drs {
80 + fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value)
81 + fmt.Fprintf(w, "// %s\n", dr.OrigName)
82 + }
83 + fmt.Fprintf(w, ")\n")
84 + return nil
85 +}
86 +
87 +type dscpRegistry struct {
88 + XMLName xml.Name `xml:"registry"`
89 + Title string `xml:"title"`
90 + Updated string `xml:"updated"`
91 + Note string `xml:"note"`
92 + RegTitle string `xml:"registry>title"`
93 + PoolRecords []struct {
94 + Name string `xml:"name"`
95 + Space string `xml:"space"`
96 + } `xml:"registry>record"`
97 + Records []struct {
98 + Name string `xml:"name"`
99 + Space string `xml:"space"`
100 + } `xml:"registry>registry>record"`
101 +}
102 +
103 +type canonDSCPRecord struct {
104 + OrigName string
105 + Name string
106 + Value int
107 +}
108 +
109 +func (drr *dscpRegistry) escape() []canonDSCPRecord {
110 + drs := make([]canonDSCPRecord, len(drr.Records))
111 + sr := strings.NewReplacer(
112 + "+", "",
113 + "-", "",
114 + "/", "",
115 + ".", "",
116 + " ", "",
117 + )
118 + for i, dr := range drr.Records {
119 + s := strings.TrimSpace(dr.Name)
120 + drs[i].OrigName = s
121 + drs[i].Name = sr.Replace(s)
122 + n, err := strconv.ParseUint(dr.Space, 2, 8)
123 + if err != nil {
124 + continue
125 + }
126 + drs[i].Value = int(n) << 2
127 + }
128 + return drs
129 +}
130 +
131 +func parseTOSTCByte(w io.Writer, r io.Reader) error {
132 + dec := xml.NewDecoder(r)
133 + var ttb tosTCByte
134 + if err := dec.Decode(&ttb); err != nil {
135 + return err
136 + }
137 + trs := ttb.escape()
138 + fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated)
139 + fmt.Fprintf(w, "const (\n")
140 + for _, tr := range trs {
141 + fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value)
142 + fmt.Fprintf(w, "// %s\n", tr.OrigKeyword)
143 + }
144 + fmt.Fprintf(w, ")\n")
145 + return nil
146 +}
147 +
148 +type tosTCByte struct {
149 + XMLName xml.Name `xml:"registry"`
150 + Title string `xml:"title"`
151 + Updated string `xml:"updated"`
152 + Note string `xml:"note"`
153 + RegTitle string `xml:"registry>title"`
154 + Records []struct {
155 + Binary string `xml:"binary"`
156 + Keyword string `xml:"keyword"`
157 + } `xml:"registry>record"`
158 +}
159 +
160 +type canonTOSTCByteRecord struct {
161 + OrigKeyword string
162 + Keyword string
163 + Value int
164 +}
165 +
166 +func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
167 + trs := make([]canonTOSTCByteRecord, len(ttb.Records))
168 + sr := strings.NewReplacer(
169 + "Capable", "",
170 + "(", "",
171 + ")", "",
172 + "+", "",
173 + "-", "",
174 + "/", "",
175 + ".", "",
176 + " ", "",
177 + )
178 + for i, tr := range ttb.Records {
179 + s := strings.TrimSpace(tr.Keyword)
180 + trs[i].OrigKeyword = s
181 + ss := strings.Split(s, " ")
182 + if len(ss) > 1 {
183 + trs[i].Keyword = strings.Join(ss[1:], " ")
184 + } else {
185 + trs[i].Keyword = ss[0]
186 + }
187 + trs[i].Keyword = sr.Replace(trs[i].Keyword)
188 + n, err := strconv.ParseUint(tr.Binary, 2, 8)
189 + if err != nil {
190 + continue
191 + }
192 + trs[i].Value = int(n)
193 + }
194 + return trs
195 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/helper.go new
+33
@@ -0,0 +1,33 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "errors"
9 + "net"
10 +)
11 +
12 +var errOpNoSupport = errors.New("operation not supported")
13 +
14 +func boolint(b bool) int {
15 + if b {
16 + return 1
17 + }
18 + return 0
19 +}
20 +
21 +func netAddrToIP16(a net.Addr) net.IP {
22 + switch v := a.(type) {
23 + case *net.UDPAddr:
24 + if ip := v.IP.To16(); ip != nil && ip.To4() == nil {
25 + return ip
26 + }
27 + case *net.IPAddr:
28 + if ip := v.IP.To16(); ip != nil && ip.To4() == nil {
29 + return ip
30 + }
31 + }
32 + return nil
33 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/helper_stub.go new
+22
@@ -0,0 +1,22 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv6
8 +
9 +func (c *genericOpt) sysfd() (int, error) {
10 + // TODO(mikio): Implement this
11 + return 0, errOpNoSupport
12 +}
13 +
14 +func (c *dgramOpt) sysfd() (int, error) {
15 + // TODO(mikio): Implement this
16 + return 0, errOpNoSupport
17 +}
18 +
19 +func (c *payloadHandler) sysfd() (int, error) {
20 + // TODO(mikio): Implement this
21 + return 0, errOpNoSupport
22 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/helper_unix.go new
+46
@@ -0,0 +1,46 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "reflect"
12 +)
13 +
14 +func (c *genericOpt) sysfd() (int, error) {
15 + switch p := c.Conn.(type) {
16 + case *net.TCPConn, *net.UDPConn, *net.IPConn:
17 + return sysfd(p)
18 + }
19 + return 0, errInvalidConnType
20 +}
21 +
22 +func (c *dgramOpt) sysfd() (int, error) {
23 + switch p := c.PacketConn.(type) {
24 + case *net.UDPConn, *net.IPConn:
25 + return sysfd(p.(net.Conn))
26 + }
27 + return 0, errInvalidConnType
28 +}
29 +
30 +func (c *payloadHandler) sysfd() (int, error) {
31 + return sysfd(c.PacketConn.(net.Conn))
32 +}
33 +
34 +func sysfd(c net.Conn) (int, error) {
35 + cv := reflect.ValueOf(c)
36 + switch ce := cv.Elem(); ce.Kind() {
37 + case reflect.Struct:
38 + nfd := ce.FieldByName("conn").FieldByName("fd")
39 + switch fe := nfd.Elem(); fe.Kind() {
40 + case reflect.Struct:
41 + fd := fe.FieldByName("sysfd")
42 + return int(fd.Int()), nil
43 + }
44 + }
45 + return 0, errInvalidConnType
46 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/helper_windows.go new
+45
@@ -0,0 +1,45 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "net"
9 + "reflect"
10 + "syscall"
11 +)
12 +
13 +func (c *genericOpt) sysfd() (syscall.Handle, error) {
14 + switch p := c.Conn.(type) {
15 + case *net.TCPConn, *net.UDPConn, *net.IPConn:
16 + return sysfd(p)
17 + }
18 + return syscall.InvalidHandle, errInvalidConnType
19 +}
20 +
21 +func (c *dgramOpt) sysfd() (syscall.Handle, error) {
22 + switch p := c.PacketConn.(type) {
23 + case *net.UDPConn, *net.IPConn:
24 + return sysfd(p.(net.Conn))
25 + }
26 + return syscall.InvalidHandle, errInvalidConnType
27 +}
28 +
29 +func (c *payloadHandler) sysfd() (syscall.Handle, error) {
30 + return sysfd(c.PacketConn.(net.Conn))
31 +}
32 +
33 +func sysfd(c net.Conn) (syscall.Handle, error) {
34 + cv := reflect.ValueOf(c)
35 + switch ce := cv.Elem(); ce.Kind() {
36 + case reflect.Struct:
37 + netfd := ce.FieldByName("conn").FieldByName("fd")
38 + switch fe := netfd.Elem(); fe.Kind() {
39 + case reflect.Struct:
40 + fd := fe.FieldByName("sysfd")
41 + return syscall.Handle(fd.Uint()), nil
42 + }
43 + }
44 + return syscall.InvalidHandle, errInvalidConnType
45 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/iana.go new
+224
@@ -0,0 +1,224 @@
1 +// go run gen.go
2 +// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3 +
4 +package ipv6
5 +
6 +// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2013-07-03
7 +const (
8 + ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable
9 + ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big
10 + ICMPTypeTimeExceeded ICMPType = 3 // Time Exceeded
11 + ICMPTypeParameterProblem ICMPType = 4 // Parameter Problem
12 + ICMPTypeEchoRequest ICMPType = 128 // Echo Request
13 + ICMPTypeEchoReply ICMPType = 129 // Echo Reply
14 + ICMPTypeMulticastListenerQuery ICMPType = 130 // Multicast Listener Query
15 + ICMPTypeMulticastListenerReport ICMPType = 131 // Multicast Listener Report
16 + ICMPTypeMulticastListenerDone ICMPType = 132 // Multicast Listener Done
17 + ICMPTypeRouterSolicitation ICMPType = 133 // Router Solicitation
18 + ICMPTypeRouterAdvertisement ICMPType = 134 // Router Advertisement
19 + ICMPTypeNeighborSolicitation ICMPType = 135 // Neighbor Solicitation
20 + ICMPTypeNeighborAdvertisement ICMPType = 136 // Neighbor Advertisement
21 + ICMPTypeRedirect ICMPType = 137 // Redirect Message
22 + ICMPTypeRouterRenumbering ICMPType = 138 // Router Renumbering
23 + ICMPTypeNodeInformationQuery ICMPType = 139 // ICMP Node Information Query
24 + ICMPTypeNodeInformationResponse ICMPType = 140 // ICMP Node Information Response
25 + ICMPTypeInverseNeighborDiscoverySolicitation ICMPType = 141 // Inverse Neighbor Discovery Solicitation Message
26 + ICMPTypeInverseNeighborDiscoveryAdvertisement ICMPType = 142 // Inverse Neighbor Discovery Advertisement Message
27 + ICMPTypeVersion2MulticastListenerReport ICMPType = 143 // Version 2 Multicast Listener Report
28 + ICMPTypeHomeAgentAddressDiscoveryRequest ICMPType = 144 // Home Agent Address Discovery Request Message
29 + ICMPTypeHomeAgentAddressDiscoveryReply ICMPType = 145 // Home Agent Address Discovery Reply Message
30 + ICMPTypeMobilePrefixSolicitation ICMPType = 146 // Mobile Prefix Solicitation
31 + ICMPTypeMobilePrefixAdvertisement ICMPType = 147 // Mobile Prefix Advertisement
32 + ICMPTypeCertificationPathSolicitation ICMPType = 148 // Certification Path Solicitation Message
33 + ICMPTypeCertificationPathAdvertisement ICMPType = 149 // Certification Path Advertisement Message
34 + ICMPTypeMulticastRouterAdvertisement ICMPType = 151 // Multicast Router Advertisement
35 + ICMPTypeMulticastRouterSolicitation ICMPType = 152 // Multicast Router Solicitation
36 + ICMPTypeMulticastRouterTermination ICMPType = 153 // Multicast Router Termination
37 + ICMPTypeFMIPv6 ICMPType = 154 // FMIPv6 Messages
38 + ICMPTypeRPLControl ICMPType = 155 // RPL Control Message
39 + ICMPTypeILNPv6LocatorUpdate ICMPType = 156 // ILNPv6 Locator Update Message
40 + ICMPTypeDuplicateAddressRequest ICMPType = 157 // Duplicate Address Request
41 + ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation
42 +)
43 +
44 +// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2013-07-03
45 +var icmpTypes = map[ICMPType]string{
46 + 1: "destination unreachable",
47 + 2: "packet too big",
48 + 3: "time exceeded",
49 + 4: "parameter problem",
50 + 128: "echo request",
51 + 129: "echo reply",
52 + 130: "multicast listener query",
53 + 131: "multicast listener report",
54 + 132: "multicast listener done",
55 + 133: "router solicitation",
56 + 134: "router advertisement",
57 + 135: "neighbor solicitation",
58 + 136: "neighbor advertisement",
59 + 137: "redirect message",
60 + 138: "router renumbering",
61 + 139: "icmp node information query",
62 + 140: "icmp node information response",
63 + 141: "inverse neighbor discovery solicitation message",
64 + 142: "inverse neighbor discovery advertisement message",
65 + 143: "version 2 multicast listener report",
66 + 144: "home agent address discovery request message",
67 + 145: "home agent address discovery reply message",
68 + 146: "mobile prefix solicitation",
69 + 147: "mobile prefix advertisement",
70 + 148: "certification path solicitation message",
71 + 149: "certification path advertisement message",
72 + 151: "multicast router advertisement",
73 + 152: "multicast router solicitation",
74 + 153: "multicast router termination",
75 + 154: "fmipv6 messages",
76 + 155: "rpl control message",
77 + 156: "ilnpv6 locator update message",
78 + 157: "duplicate address request",
79 + 158: "duplicate address confirmation",
80 +}
81 +
82 +// Protocol Numbers, Updated: 2013-02-17
83 +const (
84 + ianaProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
85 + ianaProtocolICMP = 1 // Internet Control Message
86 + ianaProtocolIGMP = 2 // Internet Group Management
87 + ianaProtocolGGP = 3 // Gateway-to-Gateway
88 + ianaProtocolIPv4 = 4 // IPv4 encapsulation
89 + ianaProtocolST = 5 // Stream
90 + ianaProtocolTCP = 6 // Transmission Control
91 + ianaProtocolCBT = 7 // CBT
92 + ianaProtocolEGP = 8 // Exterior Gateway Protocol
93 + ianaProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP)
94 + ianaProtocolBBNRCCMON = 10 // BBN RCC Monitoring
95 + ianaProtocolNVPII = 11 // Network Voice Protocol
96 + ianaProtocolPUP = 12 // PUP
97 + ianaProtocolARGUS = 13 // ARGUS
98 + ianaProtocolEMCON = 14 // EMCON
99 + ianaProtocolXNET = 15 // Cross Net Debugger
100 + ianaProtocolCHAOS = 16 // Chaos
101 + ianaProtocolUDP = 17 // User Datagram
102 + ianaProtocolMUX = 18 // Multiplexing
103 + ianaProtocolDCNMEAS = 19 // DCN Measurement Subsystems
104 + ianaProtocolHMP = 20 // Host Monitoring
105 + ianaProtocolPRM = 21 // Packet Radio Measurement
106 + ianaProtocolXNSIDP = 22 // XEROX NS IDP
107 + ianaProtocolTRUNK1 = 23 // Trunk-1
108 + ianaProtocolTRUNK2 = 24 // Trunk-2
109 + ianaProtocolLEAF1 = 25 // Leaf-1
110 + ianaProtocolLEAF2 = 26 // Leaf-2
111 + ianaProtocolRDP = 27 // Reliable Data Protocol
112 + ianaProtocolIRTP = 28 // Internet Reliable Transaction
113 + ianaProtocolISOTP4 = 29 // ISO Transport Protocol Class 4
114 + ianaProtocolNETBLT = 30 // Bulk Data Transfer Protocol
115 + ianaProtocolMFENSP = 31 // MFE Network Services Protocol
116 + ianaProtocolMERITINP = 32 // MERIT Internodal Protocol
117 + ianaProtocolDCCP = 33 // Datagram Congestion Control Protocol
118 + ianaProtocol3PC = 34 // Third Party Connect Protocol
119 + ianaProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol
120 + ianaProtocolXTP = 36 // XTP
121 + ianaProtocolDDP = 37 // Datagram Delivery Protocol
122 + ianaProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto
123 + ianaProtocolTPPP = 39 // TP++ Transport Protocol
124 + ianaProtocolIL = 40 // IL Transport Protocol
125 + ianaProtocolIPv6 = 41 // IPv6 encapsulation
126 + ianaProtocolSDRP = 42 // Source Demand Routing Protocol
127 + ianaProtocolIPv6Route = 43 // Routing Header for IPv6
128 + ianaProtocolIPv6Frag = 44 // Fragment Header for IPv6
129 + ianaProtocolIDRP = 45 // Inter-Domain Routing Protocol
130 + ianaProtocolRSVP = 46 // Reservation Protocol
131 + ianaProtocolGRE = 47 // Generic Routing Encapsulation
132 + ianaProtocolDSR = 48 // Dynamic Source Routing Protocol
133 + ianaProtocolBNA = 49 // BNA
134 + ianaProtocolESP = 50 // Encap Security Payload
135 + ianaProtocolAH = 51 // Authentication Header
136 + ianaProtocolINLSP = 52 // Integrated Net Layer Security TUBA
137 + ianaProtocolSWIPE = 53 // IP with Encryption
138 + ianaProtocolNARP = 54 // NBMA Address Resolution Protocol
139 + ianaProtocolMOBILE = 55 // IP Mobility
140 + ianaProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management
141 + ianaProtocolSKIP = 57 // SKIP
142 + ianaProtocolIPv6ICMP = 58 // ICMP for IPv6
143 + ianaProtocolIPv6NoNxt = 59 // No Next Header for IPv6
144 + ianaProtocolIPv6Opts = 60 // Destination Options for IPv6
145 + ianaProtocolCFTP = 62 // CFTP
146 + ianaProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK
147 + ianaProtocolKRYPTOLAN = 65 // Kryptolan
148 + ianaProtocolRVD = 66 // MIT Remote Virtual Disk Protocol
149 + ianaProtocolIPPC = 67 // Internet Pluribus Packet Core
150 + ianaProtocolSATMON = 69 // SATNET Monitoring
151 + ianaProtocolVISA = 70 // VISA Protocol
152 + ianaProtocolIPCV = 71 // Internet Packet Core Utility
153 + ianaProtocolCPNX = 72 // Computer Protocol Network Executive
154 + ianaProtocolCPHB = 73 // Computer Protocol Heart Beat
155 + ianaProtocolWSN = 74 // Wang Span Network
156 + ianaProtocolPVP = 75 // Packet Video Protocol
157 + ianaProtocolBRSATMON = 76 // Backroom SATNET Monitoring
158 + ianaProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary
159 + ianaProtocolWBMON = 78 // WIDEBAND Monitoring
160 + ianaProtocolWBEXPAK = 79 // WIDEBAND EXPAK
161 + ianaProtocolISOIP = 80 // ISO Internet Protocol
162 + ianaProtocolVMTP = 81 // VMTP
163 + ianaProtocolSECUREVMTP = 82 // SECURE-VMTP
164 + ianaProtocolVINES = 83 // VINES
165 + ianaProtocolTTP = 84 // TTP
166 + ianaProtocolIPTM = 84 // Protocol Internet Protocol Traffic Manager
167 + ianaProtocolNSFNETIGP = 85 // NSFNET-IGP
168 + ianaProtocolDGP = 86 // Dissimilar Gateway Protocol
169 + ianaProtocolTCF = 87 // TCF
170 + ianaProtocolEIGRP = 88 // EIGRP
171 + ianaProtocolOSPFIGP = 89 // OSPFIGP
172 + ianaProtocolSpriteRPC = 90 // Sprite RPC Protocol
173 + ianaProtocolLARP = 91 // Locus Address Resolution Protocol
174 + ianaProtocolMTP = 92 // Multicast Transport Protocol
175 + ianaProtocolAX25 = 93 // AX.25 Frames
176 + ianaProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol
177 + ianaProtocolMICP = 95 // Mobile Internetworking Control Pro.
178 + ianaProtocolSCCSP = 96 // Semaphore Communications Sec. Pro.
179 + ianaProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation
180 + ianaProtocolENCAP = 98 // Encapsulation Header
181 + ianaProtocolGMTP = 100 // GMTP
182 + ianaProtocolIFMP = 101 // Ipsilon Flow Management Protocol
183 + ianaProtocolPNNI = 102 // PNNI over IP
184 + ianaProtocolPIM = 103 // Protocol Independent Multicast
185 + ianaProtocolARIS = 104 // ARIS
186 + ianaProtocolSCPS = 105 // SCPS
187 + ianaProtocolQNX = 106 // QNX
188 + ianaProtocolAN = 107 // Active Networks
189 + ianaProtocolIPComp = 108 // IP Payload Compression Protocol
190 + ianaProtocolSNP = 109 // Sitara Networks Protocol
191 + ianaProtocolCompaqPeer = 110 // Compaq Peer Protocol
192 + ianaProtocolIPXinIP = 111 // IPX in IP
193 + ianaProtocolVRRP = 112 // Virtual Router Redundancy Protocol
194 + ianaProtocolPGM = 113 // PGM Reliable Transport Protocol
195 + ianaProtocolL2TP = 115 // Layer Two Tunneling Protocol
196 + ianaProtocolDDX = 116 // D-II Data Exchange (DDX)
197 + ianaProtocolIATP = 117 // Interactive Agent Transfer Protocol
198 + ianaProtocolSTP = 118 // Schedule Transfer Protocol
199 + ianaProtocolSRP = 119 // SpectraLink Radio Protocol
200 + ianaProtocolUTI = 120 // UTI
201 + ianaProtocolSMP = 121 // Simple Message Protocol
202 + ianaProtocolSM = 122 // SM
203 + ianaProtocolPTP = 123 // Performance Transparency Protocol
204 + ianaProtocolISIS = 124 // ISIS over IPv4
205 + ianaProtocolFIRE = 125 // FIRE
206 + ianaProtocolCRTP = 126 // Combat Radio Transport Protocol
207 + ianaProtocolCRUDP = 127 // Combat Radio User Datagram
208 + ianaProtocolSSCOPMCE = 128 // SSCOPMCE
209 + ianaProtocolIPLT = 129 // IPLT
210 + ianaProtocolSPS = 130 // Secure Packet Shield
211 + ianaProtocolPIPE = 131 // Private IP Encapsulation within IP
212 + ianaProtocolSCTP = 132 // Stream Control Transmission Protocol
213 + ianaProtocolFC = 133 // Fibre Channel
214 + ianaProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE
215 + ianaProtocolMobilityHeader = 135 // Mobility Header
216 + ianaProtocolUDPLite = 136 // UDPLite
217 + ianaProtocolMPLSinIP = 137 // MPLS-in-IP
218 + ianaProtocolMANET = 138 // MANET Protocols
219 + ianaProtocolHIP = 139 // Host Identity Protocol
220 + ianaProtocolShim6 = 140 // Shim6 Protocol
221 + ianaProtocolWESP = 141 // Wrapped Encapsulating Security Payload
222 + ianaProtocolROHC = 142 // Robust Header Compression
223 + ianaProtocolReserved = 255 // Reserved
224 +)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/iana_test.go new
+38
@@ -0,0 +1,38 @@
1 +// go run gentest.go
2 +// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3 +
4 +package ipv6_test
5 +
6 +// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25
7 +const (
8 + DiffServCS0 = 0x0 // CS0
9 + DiffServCS1 = 0x20 // CS1
10 + DiffServCS2 = 0x40 // CS2
11 + DiffServCS3 = 0x60 // CS3
12 + DiffServCS4 = 0x80 // CS4
13 + DiffServCS5 = 0xa0 // CS5
14 + DiffServCS6 = 0xc0 // CS6
15 + DiffServCS7 = 0xe0 // CS7
16 + DiffServAF11 = 0x28 // AF11
17 + DiffServAF12 = 0x30 // AF12
18 + DiffServAF13 = 0x38 // AF13
19 + DiffServAF21 = 0x48 // AF21
20 + DiffServAF22 = 0x50 // AF22
21 + DiffServAF23 = 0x58 // AF23
22 + DiffServAF31 = 0x68 // AF31
23 + DiffServAF32 = 0x70 // AF32
24 + DiffServAF33 = 0x78 // AF33
25 + DiffServAF41 = 0x88 // AF41
26 + DiffServAF42 = 0x90 // AF42
27 + DiffServAF43 = 0x98 // AF43
28 + DiffServEFPHB = 0xb8 // EF PHB
29 + DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
30 +)
31 +
32 +// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
33 +const (
34 + NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
35 + ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
36 + ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
37 + CongestionExperienced = 0x3 // CE (Congestion Experienced)
38 +)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/icmp.go new
+47
@@ -0,0 +1,47 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import "sync"
8 +
9 +// An ICMPType represents a type of ICMP message.
10 +type ICMPType int
11 +
12 +func (typ ICMPType) String() string {
13 + s, ok := icmpTypes[typ]
14 + if !ok {
15 + return "<nil>"
16 + }
17 + return s
18 +}
19 +
20 +// An ICMPFilter represents an ICMP message filter for incoming
21 +// packets.
22 +type ICMPFilter struct {
23 + mu sync.RWMutex
24 + sysICMPFilter
25 +}
26 +
27 +// Set sets the ICMP type and filter action to the filter.
28 +func (f *ICMPFilter) Set(typ ICMPType, block bool) {
29 + f.mu.Lock()
30 + f.set(typ, block)
31 + f.mu.Unlock()
32 +}
33 +
34 +// SetAll sets the filter action to the filter.
35 +func (f *ICMPFilter) SetAll(block bool) {
36 + f.mu.Lock()
37 + f.setAll(block)
38 + f.mu.Unlock()
39 +}
40 +
41 +// WillBlock reports whether the ICMP type will be blocked.
42 +func (f *ICMPFilter) WillBlock(typ ICMPType) bool {
43 + f.mu.RLock()
44 + ok := f.willBlock(typ)
45 + f.mu.RUnlock()
46 + return ok
47 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/icmp_bsd.go new
+33
@@ -0,0 +1,33 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd netbsd openbsd
6 +
7 +package ipv6
8 +
9 +type sysICMPFilter struct {
10 + Filt [8]uint32
11 +}
12 +
13 +func (f *sysICMPFilter) set(typ ICMPType, block bool) {
14 + if block {
15 + f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31)
16 + } else {
17 + f.Filt[typ>>5] |= 1 << (uint32(typ) & 31)
18 + }
19 +}
20 +
21 +func (f *sysICMPFilter) setAll(block bool) {
22 + for i := range f.Filt {
23 + if block {
24 + f.Filt[i] = 0
25 + } else {
26 + f.Filt[i] = 1<<32 - 1
27 + }
28 + }
29 +}
30 +
31 +func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
32 + return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
33 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/icmp_linux.go new
+31
@@ -0,0 +1,31 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +type sysICMPFilter struct {
8 + Data [8]uint32
9 +}
10 +
11 +func (f *sysICMPFilter) set(typ ICMPType, block bool) {
12 + if block {
13 + f.Data[typ>>5] |= 1 << (uint32(typ) & 31)
14 + } else {
15 + f.Data[typ>>5] &^= 1 << (uint32(typ) & 31)
16 + }
17 +}
18 +
19 +func (f *sysICMPFilter) setAll(block bool) {
20 + for i := range f.Data {
21 + if block {
22 + f.Data[i] = 1<<32 - 1
23 + } else {
24 + f.Data[i] = 0
25 + }
26 + }
27 +}
28 +
29 +func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
30 + return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0
31 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/icmp_stub.go new
+24
@@ -0,0 +1,24 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv6
8 +
9 +type sysICMPFilter struct {
10 + // TODO(mikio): Implement this
11 +}
12 +
13 +func (f *sysICMPFilter) set(typ ICMPType, block bool) {
14 + // TODO(mikio): Implement this
15 +}
16 +
17 +func (f *sysICMPFilter) setAll(block bool) {
18 + // TODO(mikio): Implement this
19 +}
20 +
21 +func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
22 + // TODO(mikio): Implement this
23 + return false
24 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/icmp_test.go new
+102
@@ -0,0 +1,102 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "code.google.com/p/go.net/ipv6"
9 + "net"
10 + "os"
11 + "reflect"
12 + "runtime"
13 + "sync"
14 + "testing"
15 +)
16 +
17 +var icmpStringTests = []struct {
18 + in ipv6.ICMPType
19 + out string
20 +}{
21 + {ipv6.ICMPTypeDestinationUnreachable, "destination unreachable"},
22 +
23 + {256, "<nil>"},
24 +}
25 +
26 +func TestICMPString(t *testing.T) {
27 + for _, tt := range icmpStringTests {
28 + s := tt.in.String()
29 + if s != tt.out {
30 + t.Errorf("got %s; expected %s", s, tt.out)
31 + }
32 + }
33 +}
34 +
35 +func TestICMPFilter(t *testing.T) {
36 + switch runtime.GOOS {
37 + case "plan9", "solaris", "windows":
38 + t.Skipf("not supported on %q", runtime.GOOS)
39 + }
40 +
41 + var f ipv6.ICMPFilter
42 + for _, toggle := range []bool{false, true} {
43 + f.SetAll(toggle)
44 + var wg sync.WaitGroup
45 + for _, typ := range []ipv6.ICMPType{
46 + ipv6.ICMPTypeDestinationUnreachable,
47 + ipv6.ICMPTypeEchoReply,
48 + ipv6.ICMPTypeNeighborSolicitation,
49 + ipv6.ICMPTypeDuplicateAddressConfirmation,
50 + } {
51 + wg.Add(1)
52 + go func(typ ipv6.ICMPType) {
53 + defer wg.Done()
54 + f.Set(typ, false)
55 + if f.WillBlock(typ) {
56 + t.Errorf("ipv6.ICMPFilter.Set(%v, false) failed", typ)
57 + }
58 + f.Set(typ, true)
59 + if !f.WillBlock(typ) {
60 + t.Errorf("ipv6.ICMPFilter.Set(%v, true) failed", typ)
61 + }
62 + }(typ)
63 + }
64 + wg.Wait()
65 + }
66 +}
67 +
68 +func TestSetICMPFilter(t *testing.T) {
69 + switch runtime.GOOS {
70 + case "plan9", "solaris", "windows":
71 + t.Skipf("not supported on %q", runtime.GOOS)
72 + }
73 + if !supportsIPv6 {
74 + t.Skip("ipv6 is not supported")
75 + }
76 + if os.Getuid() != 0 {
77 + t.Skip("must be root")
78 + }
79 +
80 + c, err := net.ListenPacket("ip6:ipv6-icmp", "::1")
81 + if err != nil {
82 + t.Fatalf("net.ListenPacket failed: %v", err)
83 + }
84 + defer c.Close()
85 +
86 + p := ipv6.NewPacketConn(c)
87 +
88 + var f ipv6.ICMPFilter
89 + f.SetAll(true)
90 + f.Set(ipv6.ICMPTypeEchoRequest, false)
91 + f.Set(ipv6.ICMPTypeEchoReply, false)
92 + if err := p.SetICMPFilter(&f); err != nil {
93 + t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
94 + }
95 + kf, err := p.ICMPFilter()
96 + if err != nil {
97 + t.Fatalf("ipv6.PacketConn.ICMPFilter failed: %v", err)
98 + }
99 + if !reflect.DeepEqual(kf, &f) {
100 + t.Fatalf("got unexpected filter %#v; expected %#v", kf, f)
101 + }
102 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/icmp_windows.go new
+22
@@ -0,0 +1,22 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +type sysICMPFilter struct {
8 + // TODO(mikio): Implement this
9 +}
10 +
11 +func (f *sysICMPFilter) set(typ ICMPType, block bool) {
12 + // TODO(mikio): Implement this
13 +}
14 +
15 +func (f *sysICMPFilter) setAll(block bool) {
16 + // TODO(mikio): Implement this
17 +}
18 +
19 +func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
20 + // TODO(mikio): Implement this
21 + return false
22 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/mockicmp_test.go new
+130
@@ -0,0 +1,130 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "code.google.com/p/go.net/ipv6"
9 + "errors"
10 + "net"
11 +)
12 +
13 +const (
14 + ipv6PseudoHeaderLen = 2*net.IPv6len + 8
15 + ianaProtocolIPv6ICMP = 58
16 +)
17 +
18 +func ipv6PseudoHeader(src, dst net.IP, nextHeader int) []byte {
19 + b := make([]byte, ipv6PseudoHeaderLen)
20 + copy(b[:net.IPv6len], src)
21 + copy(b[net.IPv6len:], dst)
22 + b[len(b)-1] = byte(nextHeader)
23 + return b
24 +}
25 +
26 +// icmpMessage represents an ICMP message.
27 +type icmpMessage struct {
28 + Type ipv6.ICMPType // type
29 + Code int // code
30 + Checksum int // checksum
31 + Body icmpMessageBody // body
32 +}
33 +
34 +// icmpMessageBody represents an ICMP message body.
35 +type icmpMessageBody interface {
36 + Len() int
37 + Marshal() ([]byte, error)
38 +}
39 +
40 +// Marshal returns the binary enconding of the ICMP echo request or
41 +// reply message m.
42 +func (m *icmpMessage) Marshal(psh []byte) ([]byte, error) {
43 + b := []byte{byte(m.Type), byte(m.Code), 0, 0}
44 + if psh != nil {
45 + b = append(psh, b...)
46 + }
47 + if m.Body != nil && m.Body.Len() != 0 {
48 + mb, err := m.Body.Marshal()
49 + if err != nil {
50 + return nil, err
51 + }
52 + b = append(b, mb...)
53 + }
54 + if psh == nil {
55 + return b, nil
56 + }
57 + off, l := 2*net.IPv6len, len(b)-len(psh)
58 + b[off], b[off+1], b[off+2], b[off+3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
59 + csumcv := len(b) - 1 // checksum coverage
60 + s := uint32(0)
61 + for i := 0; i < csumcv; i += 2 {
62 + s += uint32(b[i+1])<<8 | uint32(b[i])
63 + }
64 + if csumcv&1 == 0 {
65 + s += uint32(b[csumcv])
66 + }
67 + s = s>>16 + s&0xffff
68 + s = s + s>>16
69 + // Place checksum back in header; using ^= avoids the
70 + // assumption the checksum bytes are zero.
71 + b[len(psh)+2] ^= byte(^s)
72 + b[len(psh)+3] ^= byte(^s >> 8)
73 + return b[len(psh):], nil
74 +}
75 +
76 +// parseICMPMessage parses b as an ICMP message.
77 +func parseICMPMessage(b []byte) (*icmpMessage, error) {
78 + msglen := len(b)
79 + if msglen < 4 {
80 + return nil, errors.New("message too short")
81 + }
82 + m := &icmpMessage{Type: ipv6.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
83 + if msglen > 4 {
84 + var err error
85 + switch m.Type {
86 + case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply:
87 + m.Body, err = parseICMPEcho(b[4:])
88 + if err != nil {
89 + return nil, err
90 + }
91 + }
92 + }
93 + return m, nil
94 +}
95 +
96 +// imcpEcho represenets an ICMP echo request or reply message body.
97 +type icmpEcho struct {
98 + ID int // identifier
99 + Seq int // sequence number
100 + Data []byte // data
101 +}
102 +
103 +func (p *icmpEcho) Len() int {
104 + if p == nil {
105 + return 0
106 + }
107 + return 4 + len(p.Data)
108 +}
109 +
110 +// Marshal returns the binary enconding of the ICMP echo request or
111 +// reply message body p.
112 +func (p *icmpEcho) Marshal() ([]byte, error) {
113 + b := make([]byte, 4+len(p.Data))
114 + b[0], b[1] = byte(p.ID>>8), byte(p.ID)
115 + b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
116 + copy(b[4:], p.Data)
117 + return b, nil
118 +}
119 +
120 +// parseICMPEcho parses b as an ICMP echo request or reply message
121 +// body.
122 +func parseICMPEcho(b []byte) (*icmpEcho, error) {
123 + bodylen := len(b)
124 + p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
125 + if bodylen > 4 {
126 + p.Data = make([]byte, bodylen-4)
127 + copy(p.Data, b[4:])
128 + }
129 + return p, nil
130 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/mocktransponder_test.go new
+88
@@ -0,0 +1,88 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "net"
9 + "testing"
10 +)
11 +
12 +func isLinkLocalUnicast(ip net.IP) bool {
13 + return ip.To4() == nil && ip.To16() != nil && ip.IsLinkLocalUnicast()
14 +}
15 +
16 +func loopbackInterface() *net.Interface {
17 + ift, err := net.Interfaces()
18 + if err != nil {
19 + return nil
20 + }
21 + for _, ifi := range ift {
22 + if ifi.Flags&net.FlagLoopback == 0 || ifi.Flags&net.FlagUp == 0 {
23 + continue
24 + }
25 + ifat, err := ifi.Addrs()
26 + if err != nil {
27 + continue
28 + }
29 + for _, ifa := range ifat {
30 + switch ifa := ifa.(type) {
31 + case *net.IPAddr:
32 + if isLinkLocalUnicast(ifa.IP) {
33 + return &ifi
34 + }
35 + case *net.IPNet:
36 + if isLinkLocalUnicast(ifa.IP) {
37 + return &ifi
38 + }
39 + }
40 + }
41 + }
42 + return nil
43 +}
44 +
45 +func isMulticastAvailable(ifi *net.Interface) (net.IP, bool) {
46 + if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
47 + return nil, false
48 + }
49 + ifat, err := ifi.Addrs()
50 + if err != nil {
51 + return nil, false
52 + }
53 + for _, ifa := range ifat {
54 + switch ifa := ifa.(type) {
55 + case *net.IPAddr:
56 + if isLinkLocalUnicast(ifa.IP) {
57 + return ifa.IP, true
58 + }
59 + case *net.IPNet:
60 + if isLinkLocalUnicast(ifa.IP) {
61 + return ifa.IP, true
62 + }
63 + }
64 + }
65 + return nil, false
66 +}
67 +
68 +func connector(t *testing.T, network, addr string, done chan<- bool) {
69 + defer func() { done <- true }()
70 +
71 + c, err := net.Dial(network, addr)
72 + if err != nil {
73 + t.Errorf("net.Dial failed: %v", err)
74 + return
75 + }
76 + c.Close()
77 +}
78 +
79 +func acceptor(t *testing.T, ln net.Listener, done chan<- bool) {
80 + defer func() { done <- true }()
81 +
82 + c, err := ln.Accept()
83 + if err != nil {
84 + t.Errorf("net.Listener.Accept failed: %v", err)
85 + return
86 + }
87 + c.Close()
88 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/multicast_test.go new
+205
@@ -0,0 +1,205 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "bytes"
9 + "code.google.com/p/go.net/ipv6"
10 + "net"
11 + "os"
12 + "runtime"
13 + "testing"
14 + "time"
15 +)
16 +
17 +func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
18 + switch runtime.GOOS {
19 + case "freebsd": // due to a bug on loopback marking
20 + // See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065.
21 + t.Skipf("not supported on %q", runtime.GOOS)
22 + case "plan9", "solaris", "windows":
23 + t.Skipf("not supported on %q", runtime.GOOS)
24 + }
25 + if !supportsIPv6 {
26 + t.Skip("ipv6 is not supported")
27 + }
28 + ifi := loopbackInterface()
29 + if ifi == nil {
30 + t.Skipf("not available on %q", runtime.GOOS)
31 + }
32 +
33 + c, err := net.ListenPacket("udp6", "[ff02::114]:0") // see RFC 4727
34 + if err != nil {
35 + t.Fatalf("net.ListenPacket failed: %v", err)
36 + }
37 + defer c.Close()
38 +
39 + _, port, err := net.SplitHostPort(c.LocalAddr().String())
40 + if err != nil {
41 + t.Fatalf("net.SplitHostPort failed: %v", err)
42 + }
43 + dst, err := net.ResolveUDPAddr("udp6", "[ff02::114]:"+port) // see RFC 4727
44 + if err != nil {
45 + t.Fatalf("net.ResolveUDPAddr failed: %v", err)
46 + }
47 +
48 + p := ipv6.NewPacketConn(c)
49 + defer p.Close()
50 + if err := p.JoinGroup(ifi, dst); err != nil {
51 + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
52 + }
53 + if err := p.SetMulticastInterface(ifi); err != nil {
54 + t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err)
55 + }
56 + if _, err := p.MulticastInterface(); err != nil {
57 + t.Fatalf("ipv6.PacketConn.MulticastInterface failed: %v", err)
58 + }
59 + if err := p.SetMulticastLoopback(true); err != nil {
60 + t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
61 + }
62 + if _, err := p.MulticastLoopback(); err != nil {
63 + t.Fatalf("ipv6.PacketConn.MulticastLoopback failed: %v", err)
64 + }
65 +
66 + cm := ipv6.ControlMessage{
67 + TrafficClass: DiffServAF11 | CongestionExperienced,
68 + Src: net.IPv6loopback,
69 + IfIndex: ifi.Index,
70 + }
71 + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
72 + wb := []byte("HELLO-R-U-THERE")
73 +
74 + for i, toggle := range []bool{true, false, true} {
75 + if err := p.SetControlMessage(cf, toggle); err != nil {
76 + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
77 + }
78 + if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
79 + t.Fatalf("ipv6.PacketConn.SetDeadline failed: %v", err)
80 + }
81 + cm.HopLimit = i + 1
82 + if n, err := p.WriteTo(wb, &cm, dst); err != nil {
83 + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
84 + } else if n != len(wb) {
85 + t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
86 + }
87 + rb := make([]byte, 128)
88 + if n, cm, _, err := p.ReadFrom(rb); err != nil {
89 + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
90 + } else if !bytes.Equal(rb[:n], wb) {
91 + t.Fatalf("got %v; expected %v", rb[:n], wb)
92 + } else {
93 + t.Logf("rcvd cmsg: %v", cm)
94 + }
95 + }
96 +}
97 +
98 +func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
99 + switch runtime.GOOS {
100 + case "plan9", "solaris", "windows":
101 + t.Skipf("not supported on %q", runtime.GOOS)
102 + }
103 + if !supportsIPv6 {
104 + t.Skip("ipv6 is not supported")
105 + }
106 + if os.Getuid() != 0 {
107 + t.Skip("must be root")
108 + }
109 + ifi := loopbackInterface()
110 + if ifi == nil {
111 + t.Skipf("not available on %q", runtime.GOOS)
112 + }
113 +
114 + c, err := net.ListenPacket("ip6:ipv6-icmp", "::")
115 + if err != nil {
116 + t.Fatalf("net.ListenPacket failed: %v", err)
117 + }
118 + defer c.Close()
119 +
120 + dst, err := net.ResolveIPAddr("ip6", "ff02::114") // see RFC 4727
121 + if err != nil {
122 + t.Fatalf("net.ResolveIPAddr failed: %v", err)
123 + }
124 +
125 + pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
126 + p := ipv6.NewPacketConn(c)
127 + defer p.Close()
128 + if err := p.JoinGroup(ifi, dst); err != nil {
129 + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
130 + }
131 + if err := p.SetMulticastInterface(ifi); err != nil {
132 + t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err)
133 + }
134 + if _, err := p.MulticastInterface(); err != nil {
135 + t.Fatalf("ipv6.PacketConn.MulticastInterface failed: %v", err)
136 + }
137 + if err := p.SetMulticastLoopback(true); err != nil {
138 + t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
139 + }
140 + if _, err := p.MulticastLoopback(); err != nil {
141 + t.Fatalf("ipv6.PacketConn.MulticastLoopback failed: %v", err)
142 + }
143 +
144 + cm := ipv6.ControlMessage{
145 + TrafficClass: DiffServAF11 | CongestionExperienced,
146 + Src: net.IPv6loopback,
147 + IfIndex: ifi.Index,
148 + }
149 + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
150 +
151 + var f ipv6.ICMPFilter
152 + f.SetAll(true)
153 + f.Set(ipv6.ICMPTypeEchoReply, false)
154 + if err := p.SetICMPFilter(&f); err != nil {
155 + t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
156 + }
157 +
158 + var psh []byte
159 + for i, toggle := range []bool{true, false, true} {
160 + if toggle {
161 + psh = nil
162 + if err := p.SetChecksum(true, 2); err != nil {
163 + t.Fatalf("ipv6.PacketConn.SetChecksum failed: %v", err)
164 + }
165 + } else {
166 + psh = pshicmp
167 + // Some platforms never allow to disable the
168 + // kernel checksum processing.
169 + p.SetChecksum(false, -1)
170 + }
171 + wb, err := (&icmpMessage{
172 + Type: ipv6.ICMPTypeEchoRequest, Code: 0,
173 + Body: &icmpEcho{
174 + ID: os.Getpid() & 0xffff, Seq: i + 1,
175 + Data: []byte("HELLO-R-U-THERE"),
176 + },
177 + }).Marshal(psh)
178 + if err != nil {
179 + t.Fatalf("icmpMessage.Marshal failed: %v", err)
180 + }
181 + if err := p.SetControlMessage(cf, toggle); err != nil {
182 + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
183 + }
184 + if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
185 + t.Fatalf("ipv6.PacketConn.SetDeadline failed: %v", err)
186 + }
187 + cm.HopLimit = i + 1
188 + if n, err := p.WriteTo(wb, &cm, dst); err != nil {
189 + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
190 + } else if n != len(wb) {
191 + t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
192 + }
193 + rb := make([]byte, 128)
194 + if n, cm, _, err := p.ReadFrom(rb); err != nil {
195 + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
196 + } else {
197 + t.Logf("rcvd cmsg: %v", cm)
198 + if m, err := parseICMPMessage(rb[:n]); err != nil {
199 + t.Fatalf("parseICMPMessage failed: %v", err)
200 + } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
201 + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
202 + }
203 + }
204 + }
205 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/multicastlistener_test.go new
+243
@@ -0,0 +1,243 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "code.google.com/p/go.net/ipv6"
9 + "fmt"
10 + "net"
11 + "os"
12 + "runtime"
13 + "testing"
14 +)
15 +
16 +var udpMultipleGroupListenerTests = []net.Addr{
17 + &net.UDPAddr{IP: net.ParseIP("ff02::114")}, // see RFC 4727
18 + &net.UDPAddr{IP: net.ParseIP("ff02::1:114")},
19 + &net.UDPAddr{IP: net.ParseIP("ff02::2:114")},
20 +}
21 +
22 +func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
23 + switch runtime.GOOS {
24 + case "plan9", "solaris", "windows":
25 + t.Skipf("not supported on %q", runtime.GOOS)
26 + }
27 + if !supportsIPv6 {
28 + t.Skip("ipv6 is not supported")
29 + }
30 +
31 + for _, gaddr := range udpMultipleGroupListenerTests {
32 + c, err := net.ListenPacket("udp6", "[::]:0") // wildcard address with non-reusable port
33 + if err != nil {
34 + t.Fatalf("net.ListenPacket failed: %v", err)
35 + }
36 + defer c.Close()
37 +
38 + p := ipv6.NewPacketConn(c)
39 + var mift []*net.Interface
40 +
41 + ift, err := net.Interfaces()
42 + if err != nil {
43 + t.Fatalf("net.Interfaces failed: %v", err)
44 + }
45 + for i, ifi := range ift {
46 + if _, ok := isMulticastAvailable(&ifi); !ok {
47 + continue
48 + }
49 + if err := p.JoinGroup(&ifi, gaddr); err != nil {
50 + t.Fatalf("ipv6.PacketConn.JoinGroup %v on %v failed: %v", gaddr, ifi, err)
51 + }
52 + mift = append(mift, &ift[i])
53 + }
54 + for _, ifi := range mift {
55 + if err := p.LeaveGroup(ifi, gaddr); err != nil {
56 + t.Fatalf("ipv6.PacketConn.LeaveGroup %v on %v failed: %v", gaddr, ifi, err)
57 + }
58 + }
59 + }
60 +}
61 +
62 +func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
63 + switch runtime.GOOS {
64 + case "plan9", "solaris", "windows":
65 + t.Skipf("not supported on %q", runtime.GOOS)
66 + }
67 + if !supportsIPv6 {
68 + t.Skip("ipv6 is not supported")
69 + }
70 +
71 + for _, gaddr := range udpMultipleGroupListenerTests {
72 + c1, err := net.ListenPacket("udp6", "[ff02::]:1024") // wildcard address with reusable port
73 + if err != nil {
74 + t.Fatalf("net.ListenPacket failed: %v", err)
75 + }
76 + defer c1.Close()
77 +
78 + c2, err := net.ListenPacket("udp6", "[ff02::]:1024") // wildcard address with reusable port
79 + if err != nil {
80 + t.Fatalf("net.ListenPacket failed: %v", err)
81 + }
82 + defer c2.Close()
83 +
84 + var ps [2]*ipv6.PacketConn
85 + ps[0] = ipv6.NewPacketConn(c1)
86 + ps[1] = ipv6.NewPacketConn(c2)
87 + var mift []*net.Interface
88 +
89 + ift, err := net.Interfaces()
90 + if err != nil {
91 + t.Fatalf("net.Interfaces failed: %v", err)
92 + }
93 + for i, ifi := range ift {
94 + if _, ok := isMulticastAvailable(&ifi); !ok {
95 + continue
96 + }
97 + for _, p := range ps {
98 + if err := p.JoinGroup(&ifi, gaddr); err != nil {
99 + t.Fatalf("ipv6.PacketConn.JoinGroup %v on %v failed: %v", gaddr, ifi, err)
100 + }
101 + }
102 + mift = append(mift, &ift[i])
103 + }
104 + for _, ifi := range mift {
105 + for _, p := range ps {
106 + if err := p.LeaveGroup(ifi, gaddr); err != nil {
107 + t.Fatalf("ipv6.PacketConn.LeaveGroup %v on %v failed: %v", gaddr, ifi, err)
108 + }
109 + }
110 + }
111 + }
112 +}
113 +
114 +func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
115 + switch runtime.GOOS {
116 + case "plan9", "solaris", "windows":
117 + t.Skipf("not supported on %q", runtime.GOOS)
118 + }
119 + if !supportsIPv6 {
120 + t.Skip("ipv6 is not supported")
121 + }
122 +
123 + gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
124 + type ml struct {
125 + c *ipv6.PacketConn
126 + ifi *net.Interface
127 + }
128 + var mlt []*ml
129 +
130 + ift, err := net.Interfaces()
131 + if err != nil {
132 + t.Fatalf("net.Interfaces failed: %v", err)
133 + }
134 + for i, ifi := range ift {
135 + ip, ok := isMulticastAvailable(&ifi)
136 + if !ok {
137 + continue
138 + }
139 + c, err := net.ListenPacket("udp6", fmt.Sprintf("[%s%%%s]:1024", ip.String(), ifi.Name)) // unicast address with non-reusable port
140 + if err != nil {
141 + t.Fatalf("net.ListenPacket with %v failed: %v", ip, err)
142 + }
143 + defer c.Close()
144 + p := ipv6.NewPacketConn(c)
145 + if err := p.JoinGroup(&ifi, &gaddr); err != nil {
146 + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
147 + }
148 + mlt = append(mlt, &ml{p, &ift[i]})
149 + }
150 + for _, m := range mlt {
151 + if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
152 + t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
153 + }
154 + }
155 +}
156 +
157 +func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
158 + switch runtime.GOOS {
159 + case "plan9", "solaris", "windows":
160 + t.Skipf("not supported on %q", runtime.GOOS)
161 + }
162 + if !supportsIPv6 {
163 + t.Skip("ipv6 is not supported")
164 + }
165 + if os.Getuid() != 0 {
166 + t.Skip("must be root")
167 + }
168 +
169 + c, err := net.ListenPacket("ip6:ipv6-icmp", "::") // wildcard address
170 + if err != nil {
171 + t.Fatalf("net.ListenPacket failed: %v", err)
172 + }
173 + defer c.Close()
174 +
175 + p := ipv6.NewPacketConn(c)
176 + gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
177 + var mift []*net.Interface
178 +
179 + ift, err := net.Interfaces()
180 + if err != nil {
181 + t.Fatalf("net.Interfaces failed: %v", err)
182 + }
183 + for i, ifi := range ift {
184 + if _, ok := isMulticastAvailable(&ifi); !ok {
185 + continue
186 + }
187 + if err := p.JoinGroup(&ifi, &gaddr); err != nil {
188 + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
189 + }
190 + mift = append(mift, &ift[i])
191 + }
192 + for _, ifi := range mift {
193 + if err := p.LeaveGroup(ifi, &gaddr); err != nil {
194 + t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", ifi, err)
195 + }
196 + }
197 +}
198 +
199 +func TestIPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
200 + switch runtime.GOOS {
201 + case "darwin", "dragonfly", "plan9", "solaris", "windows":
202 + t.Skipf("not supported on %q", runtime.GOOS)
203 + }
204 + if !supportsIPv6 {
205 + t.Skip("ipv6 is not supported")
206 + }
207 + if os.Getuid() != 0 {
208 + t.Skip("must be root")
209 + }
210 +
211 + gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
212 + type ml struct {
213 + c *ipv6.PacketConn
214 + ifi *net.Interface
215 + }
216 + var mlt []*ml
217 +
218 + ift, err := net.Interfaces()
219 + if err != nil {
220 + t.Fatalf("net.Interfaces failed: %v", err)
221 + }
222 + for i, ifi := range ift {
223 + ip, ok := isMulticastAvailable(&ifi)
224 + if !ok {
225 + continue
226 + }
227 + c, err := net.ListenPacket("ip6:ipv6-icmp", fmt.Sprintf("%s%%%s", ip.String(), ifi.Name)) // unicast address
228 + if err != nil {
229 + t.Fatalf("net.ListenPacket failed: %v", err)
230 + }
231 + defer c.Close()
232 + p := ipv6.NewPacketConn(c)
233 + if err := p.JoinGroup(&ifi, &gaddr); err != nil {
234 + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
235 + }
236 + mlt = append(mlt, &ml{p, &ift[i]})
237 + }
238 + for _, m := range mlt {
239 + if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
240 + t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
241 + }
242 + }
243 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/multicastsockopt_test.go new
+76
@@ -0,0 +1,76 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "code.google.com/p/go.net/ipv6"
9 + "net"
10 + "os"
11 + "runtime"
12 + "testing"
13 +)
14 +
15 +var packetConnMulticastSocketOptionTests = []struct {
16 + net, proto, addr string
17 + gaddr net.Addr
18 +}{
19 + {"udp6", "", "[ff02::]:0", &net.UDPAddr{IP: net.ParseIP("ff02::114")}}, // see RFC 4727
20 + {"ip6", ":ipv6-icmp", "::", &net.IPAddr{IP: net.ParseIP("ff02::114")}}, // see RFC 4727
21 +}
22 +
23 +func TestPacketConnMulticastSocketOptions(t *testing.T) {
24 + switch runtime.GOOS {
25 + case "plan9", "solaris", "windows":
26 + t.Skipf("not supported on %q", runtime.GOOS)
27 + }
28 + if !supportsIPv6 {
29 + t.Skip("ipv6 is not supported")
30 + }
31 + ifi := loopbackInterface()
32 + if ifi == nil {
33 + t.Skipf("not available on %q", runtime.GOOS)
34 + }
35 +
36 + for _, tt := range packetConnMulticastSocketOptionTests {
37 + if tt.net == "ip6" && os.Getuid() != 0 {
38 + t.Skip("must be root")
39 + }
40 + c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
41 + if err != nil {
42 + t.Fatalf("net.ListenPacket failed: %v", err)
43 + }
44 + defer c.Close()
45 +
46 + p := ipv6.NewPacketConn(c)
47 +
48 + hoplim := 255
49 + if err := p.SetMulticastHopLimit(hoplim); err != nil {
50 + t.Fatalf("ipv6.PacketConn.SetMulticastHopLimit failed: %v", err)
51 + }
52 + if v, err := p.MulticastHopLimit(); err != nil {
53 + t.Fatalf("ipv6.PacketConn.MulticastHopLimit failed: %v", err)
54 + } else if v != hoplim {
55 + t.Fatalf("got unexpected multicast hop limit %v; expected %v", v, hoplim)
56 + }
57 +
58 + for _, toggle := range []bool{true, false} {
59 + if err := p.SetMulticastLoopback(toggle); err != nil {
60 + t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
61 + }
62 + if v, err := p.MulticastLoopback(); err != nil {
63 + t.Fatalf("ipv6.PacketConn.MulticastLoopback failed: %v", err)
64 + } else if v != toggle {
65 + t.Fatalf("got unexpected multicast loopback %v; expected %v", v, toggle)
66 + }
67 + }
68 +
69 + if err := p.JoinGroup(ifi, tt.gaddr); err != nil {
70 + t.Fatalf("ipv6.PacketConn.JoinGroup(%v, %v) failed: %v", ifi, tt.gaddr, err)
71 + }
72 + if err := p.LeaveGroup(ifi, tt.gaddr); err != nil {
73 + t.Fatalf("ipv6.PacketConn.LeaveGroup(%v, %v) failed: %v", ifi, tt.gaddr, err)
74 + }
75 + }
76 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/payload.go new
+15
@@ -0,0 +1,15 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import "net"
8 +
9 +// A payloadHandler represents the IPv6 datagram payload handler.
10 +type payloadHandler struct {
11 + net.PacketConn
12 + rawOpt
13 +}
14 +
15 +func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil }
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/payload_cmsg.go new
+70
@@ -0,0 +1,70 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build !nacl,!plan9,!windows
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// ReadFrom reads a payload of the received IPv6 datagram, from the
15 +// endpoint c, copying the payload into b. It returns the number of
16 +// bytes copied into b, the control message cm and the source address
17 +// src of the received datagram.
18 +func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
19 + if !c.ok() {
20 + return 0, nil, nil, syscall.EINVAL
21 + }
22 + oob := newControlMessage(&c.rawOpt)
23 + var oobn int
24 + switch c := c.PacketConn.(type) {
25 + case *net.UDPConn:
26 + if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
27 + return 0, nil, nil, err
28 + }
29 + case *net.IPConn:
30 + if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil {
31 + return 0, nil, nil, err
32 + }
33 + default:
34 + return 0, nil, nil, errInvalidConnType
35 + }
36 + if cm, err = parseControlMessage(oob[:oobn]); err != nil {
37 + return 0, nil, nil, err
38 + }
39 + if cm != nil {
40 + cm.Src = netAddrToIP16(src)
41 + }
42 + return
43 +}
44 +
45 +// WriteTo writes a payload of the IPv6 datagram, to the destination
46 +// address dst through the endpoint c, copying the payload from b. It
47 +// returns the number of bytes written. The control message cm allows
48 +// the IPv6 header fields and the datagram path to be specified. The
49 +// cm may be nil if control of the outgoing datagram is not required.
50 +func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
51 + if !c.ok() {
52 + return 0, syscall.EINVAL
53 + }
54 + oob := marshalControlMessage(cm)
55 + if dst == nil {
56 + return 0, errMissingAddress
57 + }
58 + switch c := c.PacketConn.(type) {
59 + case *net.UDPConn:
60 + n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
61 + case *net.IPConn:
62 + n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
63 + default:
64 + return 0, errInvalidConnType
65 + }
66 + if err != nil {
67 + return 0, err
68 + }
69 + return
70 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/payload_nocmsg.go new
+41
@@ -0,0 +1,41 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 windows
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// ReadFrom reads a payload of the received IPv6 datagram, from the
15 +// endpoint c, copying the payload into b. It returns the number of
16 +// bytes copied into b, the control message cm and the source address
17 +// src of the received datagram.
18 +func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
19 + if !c.ok() {
20 + return 0, nil, nil, syscall.EINVAL
21 + }
22 + if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
23 + return 0, nil, nil, err
24 + }
25 + return
26 +}
27 +
28 +// WriteTo writes a payload of the IPv6 datagram, to the destination
29 +// address dst through the endpoint c, copying the payload from b. It
30 +// returns the number of bytes written. The control message cm allows
31 +// the IPv6 header fields and the datagram path to be specified. The
32 +// cm may be nil if control of the outgoing datagram is not required.
33 +func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
34 + if !c.ok() {
35 + return 0, syscall.EINVAL
36 + }
37 + if dst == nil {
38 + return 0, errMissingAddress
39 + }
40 + return c.PacketConn.WriteTo(b, dst)
41 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/readwrite_test.go new
+168
@@ -0,0 +1,168 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "bytes"
9 + "code.google.com/p/go.net/ipv6"
10 + "net"
11 + "runtime"
12 + "sync"
13 + "testing"
14 +)
15 +
16 +func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
17 + c, err := net.ListenPacket("udp6", "[::1]:0")
18 + if err != nil {
19 + return nil, nil, err
20 + }
21 + dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
22 + if err != nil {
23 + c.Close()
24 + return nil, nil, err
25 + }
26 + return c, dst, nil
27 +}
28 +
29 +func BenchmarkReadWriteNetUDP(b *testing.B) {
30 + c, dst, err := benchmarkUDPListener()
31 + if err != nil {
32 + b.Fatalf("benchmarkUDPListener failed: %v", err)
33 + }
34 + defer c.Close()
35 +
36 + wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
37 + b.ResetTimer()
38 + for i := 0; i < b.N; i++ {
39 + benchmarkReadWriteNetUDP(b, c, wb, rb, dst)
40 + }
41 +}
42 +
43 +func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) {
44 + if _, err := c.WriteTo(wb, dst); err != nil {
45 + b.Fatalf("net.PacketConn.WriteTo failed: %v", err)
46 + }
47 + if _, _, err := c.ReadFrom(rb); err != nil {
48 + b.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
49 + }
50 +}
51 +
52 +func BenchmarkReadWriteIPv6UDP(b *testing.B) {
53 + c, dst, err := benchmarkUDPListener()
54 + if err != nil {
55 + b.Fatalf("benchmarkUDPListener failed: %v", err)
56 + }
57 + defer c.Close()
58 +
59 + p := ipv6.NewPacketConn(c)
60 + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
61 + if err := p.SetControlMessage(cf, true); err != nil {
62 + b.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
63 + }
64 + ifi := loopbackInterface()
65 +
66 + wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
67 + b.ResetTimer()
68 + for i := 0; i < b.N; i++ {
69 + benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi)
70 + }
71 +}
72 +
73 +func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) {
74 + cm := ipv6.ControlMessage{
75 + TrafficClass: DiffServAF11 | CongestionExperienced,
76 + HopLimit: 1,
77 + }
78 + if ifi != nil {
79 + cm.IfIndex = ifi.Index
80 + }
81 + if n, err := p.WriteTo(wb, &cm, dst); err != nil {
82 + b.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
83 + } else if n != len(wb) {
84 + b.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
85 + }
86 + if _, _, _, err := p.ReadFrom(rb); err != nil {
87 + b.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
88 + }
89 +}
90 +
91 +func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
92 + switch runtime.GOOS {
93 + case "plan9", "solaris", "windows":
94 + t.Skipf("not supported on %q", runtime.GOOS)
95 + }
96 + if !supportsIPv6 {
97 + t.Skip("ipv6 is not supported")
98 + }
99 +
100 + c, err := net.ListenPacket("udp6", "[::1]:0")
101 + if err != nil {
102 + t.Fatalf("net.ListenPacket failed: %v", err)
103 + }
104 + defer c.Close()
105 + p := ipv6.NewPacketConn(c)
106 + defer p.Close()
107 +
108 + dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
109 + if err != nil {
110 + t.Fatalf("net.ResolveUDPAddr failed: %v", err)
111 + }
112 +
113 + ifi := loopbackInterface()
114 + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
115 + wb := []byte("HELLO-R-U-THERE")
116 +
117 + var wg sync.WaitGroup
118 + reader := func() {
119 + defer wg.Done()
120 + rb := make([]byte, 128)
121 + if n, cm, _, err := p.ReadFrom(rb); err != nil {
122 + t.Errorf("ipv6.PacketConn.ReadFrom failed: %v", err)
123 + return
124 + } else if !bytes.Equal(rb[:n], wb) {
125 + t.Errorf("got %v; expected %v", rb[:n], wb)
126 + return
127 + } else {
128 + t.Logf("rcvd cmsg: %v", cm)
129 + }
130 + }
131 + writer := func(toggle bool) {
132 + defer wg.Done()
133 + cm := ipv6.ControlMessage{
134 + TrafficClass: DiffServAF11 | CongestionExperienced,
135 + Src: net.IPv6loopback,
136 + Dst: net.IPv6loopback,
137 + }
138 + if ifi != nil {
139 + cm.IfIndex = ifi.Index
140 + }
141 + if err := p.SetControlMessage(cf, toggle); err != nil {
142 + t.Errorf("ipv6.PacketConn.SetControlMessage failed: %v", err)
143 + return
144 + }
145 + if n, err := p.WriteTo(wb, &cm, dst); err != nil {
146 + t.Errorf("ipv6.PacketConn.WriteTo failed: %v", err)
147 + return
148 + } else if n != len(wb) {
149 + t.Errorf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
150 + return
151 + }
152 + }
153 +
154 + const N = 10
155 + wg.Add(N)
156 + for i := 0; i < N; i++ {
157 + go reader()
158 + }
159 + wg.Add(2 * N)
160 + for i := 0; i < 2*N; i++ {
161 + go writer(i%2 != 0)
162 + }
163 + wg.Add(N)
164 + for i := 0; i < N; i++ {
165 + go reader()
166 + }
167 + wg.Wait()
168 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt.go new
+40
@@ -0,0 +1,40 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +// Sticky socket options
8 +const (
9 + ssoTrafficClass = iota // header field for unicast packet, RFC 3542
10 + ssoHopLimit // header field for unicast packet, RFC 3493
11 + ssoMulticastInterface // outbound interface for multicast packet, RFC 3493
12 + ssoMulticastHopLimit // header field for multicast packet, RFC 3493
13 + ssoMulticastLoopback // loopback for multicast packet, RFC 3493
14 + ssoReceiveTrafficClass // header field on received packet, RFC 3542
15 + ssoReceiveHopLimit // header field on received packet, RFC 2292 or 3542
16 + ssoReceivePacketInfo // incbound or outbound packet path, RFC 2292 or 3542
17 + ssoReceivePathMTU // path mtu, RFC 3542
18 + ssoPathMTU // path mtu, RFC 3542
19 + ssoChecksum // packet checksum, RFC 2292 or 3542
20 + ssoICMPFilter // icmp filter, RFC 2292 or 3542
21 + ssoJoinGroup // any-source multicast, RFC 3493
22 + ssoLeaveGroup // any-source multicast, RFC 3493
23 + ssoMax
24 +)
25 +
26 +// Sticky socket option value types
27 +const (
28 + ssoTypeInt = iota + 1
29 + ssoTypeInterface
30 + ssoTypeICMPFilter
31 + ssoTypeMTUInfo
32 + ssoTypeIPMreq
33 +)
34 +
35 +// A sockOpt represents a binding for sticky socket option.
36 +type sockOpt struct {
37 + level int // option level
38 + name int // option name, must be equal or greater than 1
39 + typ int // option value type, must be equal or greater than 1
40 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc2292_unix.go new
+70
@@ -0,0 +1,70 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin
6 +
7 +package ipv6
8 +
9 +import (
10 + "os"
11 + "syscall"
12 + "unsafe"
13 +)
14 +
15 +func ipv6ReceiveTrafficClass(fd int) (bool, error) {
16 + return false, errOpNoSupport
17 +}
18 +
19 +func setIPv6ReceiveTrafficClass(fd int, v bool) error {
20 + return errOpNoSupport
21 +}
22 +
23 +func ipv6ReceiveHopLimit(fd int) (bool, error) {
24 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292HopLimit)
25 + if err != nil {
26 + return false, os.NewSyscallError("getsockopt", err)
27 + }
28 + return v == 1, nil
29 +}
30 +
31 +func setIPv6ReceiveHopLimit(fd int, v bool) error {
32 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292HopLimit, boolint(v)))
33 +}
34 +
35 +func ipv6ReceivePacketInfo(fd int) (bool, error) {
36 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292PacketInfo)
37 + if err != nil {
38 + return false, os.NewSyscallError("getsockopt", err)
39 + }
40 + return v == 1, nil
41 +}
42 +
43 +func setIPv6ReceivePacketInfo(fd int, v bool) error {
44 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292PacketInfo, boolint(v)))
45 +}
46 +
47 +func ipv6PathMTU(fd int) (int, error) {
48 + return 0, errOpNoSupport
49 +}
50 +
51 +func ipv6ReceivePathMTU(fd int) (bool, error) {
52 + return false, errOpNoSupport
53 +}
54 +
55 +func setIPv6ReceivePathMTU(fd int, v bool) error {
56 + return errOpNoSupport
57 +}
58 +
59 +func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
60 + var v ICMPFilter
61 + l := sysSockoptLen(sysSizeofICMPFilter)
62 + if err := getsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&v.sysICMPFilter), &l); err != nil {
63 + return nil, os.NewSyscallError("getsockopt", err)
64 + }
65 + return &v, nil
66 +}
67 +
68 +func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
69 + return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&f.sysICMPFilter), sysSizeofICMPFilter))
70 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3493_bsd.go new
+19
@@ -0,0 +1,19 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "os"
11 + "syscall"
12 +)
13 +
14 +func setIPv6Checksum(fd int, on bool, offset int) error {
15 + if !on {
16 + offset = -1
17 + }
18 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptChecksum, offset))
19 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3493_linux.go new
+17
@@ -0,0 +1,17 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "os"
9 + "syscall"
10 +)
11 +
12 +func setIPv6Checksum(fd int, on bool, offset int) error {
13 + if !on {
14 + offset = -1
15 + }
16 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolReserved, sysSockoptChecksum, offset))
17 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3493_unix.go new
+115
@@ -0,0 +1,115 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "os"
12 + "syscall"
13 + "unsafe"
14 +)
15 +
16 +func ipv6TrafficClass(fd int) (int, error) {
17 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptTrafficClass)
18 + if err != nil {
19 + return 0, os.NewSyscallError("getsockopt", err)
20 + }
21 + return v, nil
22 +}
23 +
24 +func setIPv6TrafficClass(fd, v int) error {
25 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptTrafficClass, v))
26 +}
27 +
28 +func ipv6HopLimit(fd int) (int, error) {
29 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit)
30 + if err != nil {
31 + return 0, os.NewSyscallError("getsockopt", err)
32 + }
33 + return v, nil
34 +}
35 +
36 +func setIPv6HopLimit(fd, v int) error {
37 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, v))
38 +}
39 +
40 +func ipv6Checksum(fd int) (bool, int, error) {
41 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptChecksum)
42 + if err != nil {
43 + return false, 0, os.NewSyscallError("getsockopt", err)
44 + }
45 + on := true
46 + if v == -1 {
47 + on = false
48 + }
49 + return on, v, nil
50 +}
51 +
52 +func ipv6MulticastHopLimit(fd int) (int, error) {
53 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit)
54 + if err != nil {
55 + return 0, os.NewSyscallError("getsockopt", err)
56 + }
57 + return v, nil
58 +}
59 +
60 +func setIPv6MulticastHopLimit(fd, v int) error {
61 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, v))
62 +}
63 +
64 +func ipv6MulticastInterface(fd int) (*net.Interface, error) {
65 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface)
66 + if err != nil {
67 + return nil, os.NewSyscallError("getsockopt", err)
68 + }
69 + if v == 0 {
70 + return nil, nil
71 + }
72 + ifi, err := net.InterfaceByIndex(v)
73 + if err != nil {
74 + return nil, err
75 + }
76 + return ifi, nil
77 +}
78 +
79 +func setIPv6MulticastInterface(fd int, ifi *net.Interface) error {
80 + var v int
81 + if ifi != nil {
82 + v = ifi.Index
83 + }
84 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, v))
85 +}
86 +
87 +func ipv6MulticastLoopback(fd int) (bool, error) {
88 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback)
89 + if err != nil {
90 + return false, os.NewSyscallError("getsockopt", err)
91 + }
92 + return v == 1, nil
93 +}
94 +
95 +func setIPv6MulticastLoopback(fd int, v bool) error {
96 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, boolint(v)))
97 +}
98 +
99 +func joinIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
100 + mreq := sysMulticastReq{}
101 + copy(mreq.IP[:], grp)
102 + if ifi != nil {
103 + mreq.IfIndex = uint32(ifi.Index)
104 + }
105 + return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptJoinGroup, unsafe.Pointer(&mreq), sysSizeofMulticastReq))
106 +}
107 +
108 +func leaveIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
109 + mreq := sysMulticastReq{}
110 + copy(mreq.IP[:], grp)
111 + if ifi != nil {
112 + mreq.IfIndex = uint32(ifi.Index)
113 + }
114 + return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptLeaveGroup, unsafe.Pointer(&mreq), sysSizeofMulticastReq))
115 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3493_windows.go new
+116
@@ -0,0 +1,116 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "net"
9 + "os"
10 + "syscall"
11 + "unsafe"
12 +)
13 +
14 +func ipv6TrafficClass(fd syscall.Handle) (int, error) {
15 + // TODO(mikio): Implement this
16 + return 0, syscall.EWINDOWS
17 +}
18 +
19 +func setIPv6TrafficClass(fd syscall.Handle, v int) error {
20 + // TODO(mikio): Implement this
21 + return syscall.EWINDOWS
22 +}
23 +
24 +func ipv6HopLimit(fd syscall.Handle) (int, error) {
25 + var v int32
26 + l := int32(4)
27 + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
28 + return 0, os.NewSyscallError("getsockopt", err)
29 + }
30 + return int(v), nil
31 +}
32 +
33 +func setIPv6HopLimit(fd syscall.Handle, v int) error {
34 + vv := int32(v)
35 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, (*byte)(unsafe.Pointer(&vv)), 4))
36 +}
37 +
38 +func ipv6Checksum(fd syscall.Handle) (bool, int, error) {
39 + // TODO(mikio): Implement this
40 + return false, 0, syscall.EWINDOWS
41 +}
42 +
43 +func ipv6MulticastHopLimit(fd syscall.Handle) (int, error) {
44 + var v int32
45 + l := int32(4)
46 + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
47 + return 0, os.NewSyscallError("getsockopt", err)
48 + }
49 + return int(v), nil
50 +}
51 +
52 +func setIPv6MulticastHopLimit(fd syscall.Handle, v int) error {
53 + vv := int32(v)
54 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, (*byte)(unsafe.Pointer(&vv)), 4))
55 +}
56 +
57 +func ipv6MulticastInterface(fd syscall.Handle) (*net.Interface, error) {
58 + var v int32
59 + l := int32(4)
60 + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
61 + return nil, os.NewSyscallError("getsockopt", err)
62 + }
63 + if v == 0 {
64 + return nil, nil
65 + }
66 + ifi, err := net.InterfaceByIndex(int(v))
67 + if err != nil {
68 + return nil, err
69 + }
70 + return ifi, nil
71 +}
72 +
73 +func setIPv6MulticastInterface(fd syscall.Handle, ifi *net.Interface) error {
74 + var v int32
75 + if ifi != nil {
76 + v = int32(ifi.Index)
77 + }
78 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v)), 4))
79 +}
80 +
81 +func ipv6MulticastLoopback(fd syscall.Handle) (bool, error) {
82 + var v int32
83 + l := int32(4)
84 + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
85 + return false, os.NewSyscallError("getsockopt", err)
86 + }
87 + return v == 1, nil
88 +}
89 +
90 +func setIPv6MulticastLoopback(fd syscall.Handle, v bool) error {
91 + vv := int32(boolint(v))
92 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&vv)), 4))
93 +}
94 +
95 +func joinIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
96 + mreq := sysMulticastReq{}
97 + copy(mreq.IP[:], grp)
98 + if ifi != nil {
99 + mreq.IfIndex = uint32(ifi.Index)
100 + }
101 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptJoinGroup, (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofMulticastReq)))
102 +}
103 +
104 +func leaveIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
105 + mreq := sysMulticastReq{}
106 + copy(mreq.IP[:], grp)
107 + if ifi != nil {
108 + mreq.IfIndex = uint32(ifi.Index)
109 + }
110 + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptLeaveGroup, (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofMulticastReq)))
111 +}
112 +
113 +func setIPv6Checksum(fd syscall.Handle, on bool, offset int) error {
114 + // TODO(mikio): Implement this
115 + return syscall.EWINDOWS
116 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3542_stub.go new
+12
@@ -0,0 +1,12 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build nacl plan9 solaris
6 +
7 +package ipv6
8 +
9 +func ipv6PathMTU(fd int) (int, error) {
10 + // TODO(mikio): Implement this
11 + return 0, errOpNoSupport
12 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3542_unix.go new
+83
@@ -0,0 +1,83 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "os"
11 + "syscall"
12 + "unsafe"
13 +)
14 +
15 +func ipv6ReceiveTrafficClass(fd int) (bool, error) {
16 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveTrafficClass)
17 + if err != nil {
18 + return false, os.NewSyscallError("getsockopt", err)
19 + }
20 + return v == 1, nil
21 +}
22 +
23 +func setIPv6ReceiveTrafficClass(fd int, v bool) error {
24 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveTrafficClass, boolint(v)))
25 +}
26 +
27 +func ipv6ReceiveHopLimit(fd int) (bool, error) {
28 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveHopLimit)
29 + if err != nil {
30 + return false, os.NewSyscallError("getsockopt", err)
31 + }
32 + return v == 1, nil
33 +}
34 +
35 +func setIPv6ReceiveHopLimit(fd int, v bool) error {
36 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveHopLimit, boolint(v)))
37 +}
38 +
39 +func ipv6ReceivePacketInfo(fd int) (bool, error) {
40 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePacketInfo)
41 + if err != nil {
42 + return false, os.NewSyscallError("getsockopt", err)
43 + }
44 + return v == 1, nil
45 +}
46 +
47 +func setIPv6ReceivePacketInfo(fd int, v bool) error {
48 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePacketInfo, boolint(v)))
49 +}
50 +
51 +func ipv6PathMTU(fd int) (int, error) {
52 + var v sysMTUInfo
53 + l := sysSockoptLen(sysSizeofMTUInfo)
54 + if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptPathMTU, unsafe.Pointer(&v), &l); err != nil {
55 + return 0, os.NewSyscallError("getsockopt", err)
56 + }
57 + return int(v.MTU), nil
58 +}
59 +
60 +func ipv6ReceivePathMTU(fd int) (bool, error) {
61 + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePathMTU)
62 + if err != nil {
63 + return false, os.NewSyscallError("getsockopt", err)
64 + }
65 + return v == 1, nil
66 +}
67 +
68 +func setIPv6ReceivePathMTU(fd int, v bool) error {
69 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePathMTU, boolint(v)))
70 +}
71 +
72 +func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
73 + var v ICMPFilter
74 + l := sysSockoptLen(sysSizeofICMPFilter)
75 + if err := getsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&v.sysICMPFilter), &l); err != nil {
76 + return nil, os.NewSyscallError("getsockopt", err)
77 + }
78 + return &v, nil
79 +}
80 +
81 +func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
82 + return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&f.sysICMPFilter), sysSizeofICMPFilter))
83 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_rfc3542_windows.go new
+62
@@ -0,0 +1,62 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import "syscall"
8 +
9 +func ipv6ReceiveTrafficClass(fd syscall.Handle) (bool, error) {
10 + // TODO(mikio): Implement this
11 + return false, syscall.EWINDOWS
12 +}
13 +
14 +func setIPv6ReceiveTrafficClass(fd syscall.Handle, v bool) error {
15 + // TODO(mikio): Implement this
16 + return syscall.EWINDOWS
17 +}
18 +
19 +func ipv6ReceiveHopLimit(fd syscall.Handle) (bool, error) {
20 + // TODO(mikio): Implement this
21 + return false, syscall.EWINDOWS
22 +}
23 +
24 +func setIPv6ReceiveHopLimit(fd syscall.Handle, v bool) error {
25 + // TODO(mikio): Implement this
26 + return syscall.EWINDOWS
27 +}
28 +
29 +func ipv6ReceivePacketInfo(fd syscall.Handle) (bool, error) {
30 + // TODO(mikio): Implement this
31 + return false, syscall.EWINDOWS
32 +}
33 +
34 +func setIPv6ReceivePacketInfo(fd syscall.Handle, v bool) error {
35 + // TODO(mikio): Implement this
36 + return syscall.EWINDOWS
37 +}
38 +
39 +func ipv6PathMTU(fd syscall.Handle) (int, error) {
40 + // TODO(mikio): Implement this
41 + return 0, syscall.EWINDOWS
42 +}
43 +
44 +func ipv6ReceivePathMTU(fd syscall.Handle) (bool, error) {
45 + // TODO(mikio): Implement this
46 + return false, syscall.EWINDOWS
47 +}
48 +
49 +func setIPv6ReceivePathMTU(fd syscall.Handle, v bool) error {
50 + // TODO(mikio): Implement this
51 + return syscall.EWINDOWS
52 +}
53 +
54 +func ipv6ICMPFilter(fd syscall.Handle) (*ICMPFilter, error) {
55 + // TODO(mikio): Implement this
56 + return nil, syscall.EWINDOWS
57 +}
58 +
59 +func setIPv6ICMPFilter(fd syscall.Handle, f *ICMPFilter) error {
60 + // TODO(mikio): Implement this
61 + return syscall.EWINDOWS
62 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sockopt_test.go new
+136
@@ -0,0 +1,136 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "code.google.com/p/go.net/ipv6"
9 + "net"
10 + "os"
11 + "runtime"
12 + "testing"
13 +)
14 +
15 +var supportsIPv6 bool
16 +
17 +func init() {
18 + if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
19 + ln.Close()
20 + supportsIPv6 = true
21 + }
22 +}
23 +
24 +var condFatalf = func() func(*testing.T, string, ...interface{}) {
25 + // A few APIs are not implemented yet on some platforms.
26 + switch runtime.GOOS {
27 + case "darwin", "plan9", "solaris", "windows":
28 + return (*testing.T).Logf
29 + }
30 + return (*testing.T).Fatalf
31 +}()
32 +
33 +func TestConnInitiatorPathMTU(t *testing.T) {
34 + switch runtime.GOOS {
35 + case "plan9", "solaris", "windows":
36 + t.Skipf("not supported on %q", runtime.GOOS)
37 + }
38 + if !supportsIPv6 {
39 + t.Skip("ipv6 is not supported")
40 + }
41 +
42 + ln, err := net.Listen("tcp6", "[::1]:0")
43 + if err != nil {
44 + t.Fatalf("net.Listen failed: %v", err)
45 + }
46 + defer ln.Close()
47 +
48 + done := make(chan bool)
49 + go acceptor(t, ln, done)
50 +
51 + c, err := net.Dial("tcp6", ln.Addr().String())
52 + if err != nil {
53 + t.Fatalf("net.Dial failed: %v", err)
54 + }
55 + defer c.Close()
56 +
57 + if pmtu, err := ipv6.NewConn(c).PathMTU(); err != nil {
58 + condFatalf(t, "ipv6.Conn.PathMTU failed: %v", err)
59 + } else {
60 + t.Logf("path mtu for %v: %v", c.RemoteAddr(), pmtu)
61 + }
62 +
63 + <-done
64 +}
65 +
66 +func TestConnResponderPathMTU(t *testing.T) {
67 + switch runtime.GOOS {
68 + case "plan9", "solaris", "windows":
69 + t.Skipf("not supported on %q", runtime.GOOS)
70 + }
71 + if !supportsIPv6 {
72 + t.Skip("ipv6 is not supported")
73 + }
74 +
75 + ln, err := net.Listen("tcp6", "[::1]:0")
76 + if err != nil {
77 + t.Fatalf("net.Listen failed: %v", err)
78 + }
79 + defer ln.Close()
80 +
81 + done := make(chan bool)
82 + go connector(t, "tcp6", ln.Addr().String(), done)
83 +
84 + c, err := ln.Accept()
85 + if err != nil {
86 + t.Fatalf("net.Accept failed: %v", err)
87 + }
88 + defer c.Close()
89 +
90 + if pmtu, err := ipv6.NewConn(c).PathMTU(); err != nil {
91 + condFatalf(t, "ipv6.Conn.PathMTU failed: %v", err)
92 + } else {
93 + t.Logf("path mtu for %v: %v", c.RemoteAddr(), pmtu)
94 + }
95 +
96 + <-done
97 +}
98 +
99 +func TestPacketConnChecksum(t *testing.T) {
100 + switch runtime.GOOS {
101 + case "plan9", "solaris", "windows":
102 + t.Skipf("not supported on %q", runtime.GOOS)
103 + }
104 + if !supportsIPv6 {
105 + t.Skip("ipv6 is not supported")
106 + }
107 + if os.Getuid() != 0 {
108 + t.Skip("must be root")
109 + }
110 +
111 + c, err := net.ListenPacket("ip6:89", "::") // OSPF for IPv6
112 + if err != nil {
113 + t.Fatalf("net.ListenPacket failed: %v", err)
114 + }
115 + defer c.Close()
116 +
117 + p := ipv6.NewPacketConn(c)
118 + offset := 12 // see RFC 5340
119 +
120 + for _, toggle := range []bool{false, true} {
121 + if err := p.SetChecksum(toggle, offset); err != nil {
122 + if toggle {
123 + t.Fatalf("ipv6.PacketConn.SetChecksum(%v, %v) failed: %v", toggle, offset, err)
124 + } else {
125 + // Some platforms never allow to disable the kernel
126 + // checksum processing.
127 + t.Logf("ipv6.PacketConn.SetChecksum(%v, %v) failed: %v", toggle, offset, err)
128 + }
129 + }
130 + if on, offset, err := p.Checksum(); err != nil {
131 + t.Fatalf("ipv6.PacketConn.Checksum failed: %v", err)
132 + } else {
133 + t.Logf("kernel checksum processing enabled=%v, offset=%v", on, offset)
134 + }
135 + }
136 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sys.go new
+23
@@ -0,0 +1,23 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +type sysSockoptLen uint32
8 +
9 +const (
10 + sysSizeofPacketInfo = 0x14
11 + sysSizeofMulticastReq = 0x14
12 + sysSizeofICMPFilter = 0x20
13 +)
14 +
15 +type sysPacketInfo struct {
16 + IP [16]byte
17 + IfIndex uint32
18 +}
19 +
20 +type sysMulticastReq struct {
21 + IP [16]byte
22 + IfIndex uint32
23 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sys_bsd.go new
+37
@@ -0,0 +1,37 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build dragonfly freebsd netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "net"
11 + "syscall"
12 +)
13 +
14 +// RFC 3542 options
15 +const (
16 + // See /usr/include/netinet6/in6.h.
17 + sysSockoptReceiveTrafficClass = syscall.IPV6_RECVTCLASS
18 + sysSockoptTrafficClass = syscall.IPV6_TCLASS
19 + sysSockoptReceiveHopLimit = syscall.IPV6_RECVHOPLIMIT
20 + sysSockoptHopLimit = syscall.IPV6_HOPLIMIT
21 + sysSockoptReceivePacketInfo = syscall.IPV6_RECVPKTINFO
22 + sysSockoptPacketInfo = syscall.IPV6_PKTINFO
23 + sysSockoptReceivePathMTU = syscall.IPV6_RECVPATHMTU
24 + sysSockoptPathMTU = syscall.IPV6_PATHMTU
25 + sysSockoptNextHop = syscall.IPV6_NEXTHOP
26 + sysSockoptChecksum = syscall.IPV6_CHECKSUM
27 +
28 + // See /usr/include/netinet6/in6.h.
29 + sysSockoptICMPFilter = 0x12 // syscall.ICMP6_FILTER
30 +)
31 +
32 +func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
33 + sa.Len = syscall.SizeofSockaddrInet6
34 + sa.Family = syscall.AF_INET6
35 + copy(sa.Addr[:], ip)
36 + sa.Scope_id = uint32(ifindex)
37 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sys_darwin.go new
+43
@@ -0,0 +1,43 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +// RFC 2292 options
13 +const (
14 + // See /usr/include/netinet6/in6.h.
15 + sysSockopt2292HopLimit = syscall.IPV6_2292HOPLIMIT
16 + sysSockopt2292PacketInfo = syscall.IPV6_2292PKTINFO
17 + sysSockopt2292NextHop = syscall.IPV6_2292NEXTHOP
18 +)
19 +
20 +// RFC 3542 options
21 +const (
22 + // See /usr/include/netinet6/in6.h.
23 + sysSockoptReceiveTrafficClass = 0x23 // IPV6_RECVTCLASS
24 + sysSockoptTrafficClass = 0x24 // IPV6_TCLASS
25 + sysSockoptReceiveHopLimit = 0x25 // IPV6_RECVHOPLIMIT
26 + sysSockoptHopLimit = 0x2f // IPV6_HOPLIMIT
27 + sysSockoptReceivePacketInfo = 0x3d // IPV6_RECVPKTINFO
28 + sysSockoptPacketInfo = 0x2e // IPV6_PKTINFO
29 + sysSockoptReceivePathMTU = 0x2b // IPV6_RECVPATHMTU
30 + sysSockoptPathMTU = 0x2c // IPV6_PATHMTU
31 + sysSockoptNextHop = 0x30 // IPV6_NEXTHOP
32 + sysSockoptChecksum = 0x1a // IPV6_CHECKSUM
33 +
34 + // See /usr/include/netinet6/in6.h.
35 + sysSockoptICMPFilter = 0x12 // ICMP6_FILTER
36 +)
37 +
38 +func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
39 + sa.Len = syscall.SizeofSockaddrInet6
40 + sa.Family = syscall.AF_INET6
41 + copy(sa.Addr[:], ip)
42 + sa.Scope_id = uint32(ifindex)
43 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sys_linux.go new
+34
@@ -0,0 +1,34 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +// RFC 3542 options
13 +const (
14 + // See /usr/include/linux/ipv6.h,in6.h.
15 + sysSockoptReceiveTrafficClass = syscall.IPV6_RECVTCLASS
16 + sysSockoptTrafficClass = syscall.IPV6_TCLASS
17 + sysSockoptReceiveHopLimit = syscall.IPV6_RECVHOPLIMIT
18 + sysSockoptHopLimit = syscall.IPV6_HOPLIMIT
19 + sysSockoptReceivePacketInfo = syscall.IPV6_RECVPKTINFO
20 + sysSockoptPacketInfo = syscall.IPV6_PKTINFO
21 + sysSockoptReceivePathMTU = 0x3c // IPV6_RECVPATHMTU
22 + sysSockoptPathMTU = 0x3d // IPV6_PATHMTU
23 + sysSockoptNextHop = syscall.IPV6_NEXTHOP
24 + sysSockoptChecksum = syscall.IPV6_CHECKSUM
25 +
26 + // See /usr/include/linux/icmpv6.h.
27 + sysSockoptICMPFilter = 0x1 // syscall.ICMPV6_FILTER
28 +)
29 +
30 +func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
31 + sa.Family = syscall.AF_INET6
32 + copy(sa.Addr[:], ip)
33 + sa.Scope_id = uint32(ifindex)
34 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sys_unix.go new
+26
@@ -0,0 +1,26 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import "syscall"
10 +
11 +// RFC 3493 options
12 +const (
13 + sysSockoptUnicastHopLimit = syscall.IPV6_UNICAST_HOPS
14 + sysSockoptMulticastHopLimit = syscall.IPV6_MULTICAST_HOPS
15 + sysSockoptMulticastInterface = syscall.IPV6_MULTICAST_IF
16 + sysSockoptMulticastLoopback = syscall.IPV6_MULTICAST_LOOP
17 + sysSockoptJoinGroup = syscall.IPV6_JOIN_GROUP
18 + sysSockoptLeaveGroup = syscall.IPV6_LEAVE_GROUP
19 +)
20 +
21 +const sysSizeofMTUInfo = 0x20
22 +
23 +type sysMTUInfo struct {
24 + Addr syscall.RawSockaddrInet6
25 + MTU uint32
26 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/sys_windows.go new
+33
@@ -0,0 +1,33 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "net"
9 + "syscall"
10 +)
11 +
12 +// RFC 3493 options
13 +const (
14 + // See ws2tcpip.h.
15 + sysSockoptUnicastHopLimit = syscall.IPV6_UNICAST_HOPS
16 + sysSockoptMulticastHopLimit = syscall.IPV6_MULTICAST_HOPS
17 + sysSockoptMulticastInterface = syscall.IPV6_MULTICAST_IF
18 + sysSockoptMulticastLoopback = syscall.IPV6_MULTICAST_LOOP
19 + sysSockoptJoinGroup = syscall.IPV6_JOIN_GROUP
20 + sysSockoptLeaveGroup = syscall.IPV6_LEAVE_GROUP
21 +)
22 +
23 +// RFC 3542 options
24 +const (
25 + // See ws2tcpip.h.
26 + sysSockoptPacketInfo = 0x13 // IPV6_PKTINFO
27 +)
28 +
29 +func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
30 + sa.Family = syscall.AF_INET6
31 + copy(sa.Addr[:], ip)
32 + sa.Scope_id = uint32(ifindex)
33 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/syscall_linux_386.go new
+31
@@ -0,0 +1,31 @@
1 +// Copyright 2009 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6
6 +
7 +import (
8 + "syscall"
9 + "unsafe"
10 +)
11 +
12 +const (
13 + sysGETSOCKOPT = 0xf
14 + sysSETSOCKOPT = 0xe
15 +)
16 +
17 +func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
18 +
19 +func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
20 + if _, errno := socketcall(sysGETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
21 + return error(errno)
22 + }
23 + return nil
24 +}
25 +
26 +func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
27 + if _, errno := socketcall(sysSETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
28 + return error(errno)
29 + }
30 + return nil
31 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/syscall_unix.go new
+26
@@ -0,0 +1,26 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build darwin dragonfly freebsd linux,amd64 linux,arm netbsd openbsd
6 +
7 +package ipv6
8 +
9 +import (
10 + "syscall"
11 + "unsafe"
12 +)
13 +
14 +func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
15 + if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
16 + return error(errno)
17 + }
18 + return nil
19 +}
20 +
21 +func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
22 + if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
23 + return error(errno)
24 + }
25 + return nil
26 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/thunk_linux_386.s new
+8
@@ -0,0 +1,8 @@
1 +// Copyright 2014 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// +build go1.2
6 +
7 +TEXT ·socketcall(SB),4,$0-36
8 + JMP syscall·socketcall(SB)
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/unicast_test.go new
+172
@@ -0,0 +1,172 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "bytes"
9 + "code.google.com/p/go.net/ipv6"
10 + "net"
11 + "os"
12 + "runtime"
13 + "testing"
14 + "time"
15 +)
16 +
17 +func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
18 + switch runtime.GOOS {
19 + case "plan9", "solaris", "windows":
20 + t.Skipf("not supported on %q", runtime.GOOS)
21 + }
22 + if !supportsIPv6 {
23 + t.Skip("ipv6 is not supported")
24 + }
25 +
26 + c, err := net.ListenPacket("udp6", "[::1]:0")
27 + if err != nil {
28 + t.Fatalf("net.ListenPacket failed: %v", err)
29 + }
30 + defer c.Close()
31 + p := ipv6.NewPacketConn(c)
32 + defer p.Close()
33 +
34 + dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
35 + if err != nil {
36 + t.Fatalf("net.ResolveUDPAddr failed: %v", err)
37 + }
38 +
39 + cm := ipv6.ControlMessage{
40 + TrafficClass: DiffServAF11 | CongestionExperienced,
41 + Src: net.IPv6loopback,
42 + Dst: net.IPv6loopback,
43 + }
44 + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
45 + ifi := loopbackInterface()
46 + if ifi != nil {
47 + cm.IfIndex = ifi.Index
48 + }
49 + wb := []byte("HELLO-R-U-THERE")
50 +
51 + for i, toggle := range []bool{true, false, true} {
52 + if err := p.SetControlMessage(cf, toggle); err != nil {
53 + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
54 + }
55 + cm.HopLimit = i + 1
56 + if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
57 + t.Fatalf("ipv6.PacketConn.SetWriteDeadline failed: %v", err)
58 + }
59 + if n, err := p.WriteTo(wb, &cm, dst); err != nil {
60 + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
61 + } else if n != len(wb) {
62 + t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
63 + }
64 + rb := make([]byte, 128)
65 + if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
66 + t.Fatalf("ipv6.PacketConn.SetReadDeadline failed: %v", err)
67 + }
68 + if n, cm, _, err := p.ReadFrom(rb); err != nil {
69 + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
70 + } else if !bytes.Equal(rb[:n], wb) {
71 + t.Fatalf("got %v; expected %v", rb[:n], wb)
72 + } else {
73 + t.Logf("rcvd cmsg: %v", cm)
74 + }
75 + }
76 +}
77 +
78 +func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
79 + switch runtime.GOOS {
80 + case "plan9", "solaris", "windows":
81 + t.Skipf("not supported on %q", runtime.GOOS)
82 + }
83 + if !supportsIPv6 {
84 + t.Skip("ipv6 is not supported")
85 + }
86 + if os.Getuid() != 0 {
87 + t.Skip("must be root")
88 + }
89 +
90 + c, err := net.ListenPacket("ip6:ipv6-icmp", "::1")
91 + if err != nil {
92 + t.Fatalf("net.ListenPacket failed: %v", err)
93 + }
94 + defer c.Close()
95 + p := ipv6.NewPacketConn(c)
96 + defer p.Close()
97 +
98 + dst, err := net.ResolveIPAddr("ip6", "::1")
99 + if err != nil {
100 + t.Fatalf("net.ResolveIPAddr failed: %v", err)
101 + }
102 +
103 + pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
104 + cm := ipv6.ControlMessage{
105 + TrafficClass: DiffServAF11 | CongestionExperienced,
106 + Src: net.IPv6loopback,
107 + Dst: net.IPv6loopback,
108 + }
109 + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
110 + ifi := loopbackInterface()
111 + if ifi != nil {
112 + cm.IfIndex = ifi.Index
113 + }
114 +
115 + var f ipv6.ICMPFilter
116 + f.SetAll(true)
117 + f.Set(ipv6.ICMPTypeEchoReply, false)
118 + if err := p.SetICMPFilter(&f); err != nil {
119 + t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
120 + }
121 +
122 + var psh []byte
123 + for i, toggle := range []bool{true, false, true} {
124 + if toggle {
125 + psh = nil
126 + if err := p.SetChecksum(true, 2); err != nil {
127 + t.Fatalf("ipv6.PacketConn.SetChecksum failed: %v", err)
128 + }
129 + } else {
130 + psh = pshicmp
131 + // Some platforms never allow to disable the
132 + // kernel checksum processing.
133 + p.SetChecksum(false, -1)
134 + }
135 + wb, err := (&icmpMessage{
136 + Type: ipv6.ICMPTypeEchoRequest, Code: 0,
137 + Body: &icmpEcho{
138 + ID: os.Getpid() & 0xffff, Seq: i + 1,
139 + Data: []byte("HELLO-R-U-THERE"),
140 + },
141 + }).Marshal(psh)
142 + if err != nil {
143 + t.Fatalf("icmpMessage.Marshal failed: %v", err)
144 + }
145 + if err := p.SetControlMessage(cf, toggle); err != nil {
146 + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
147 + }
148 + cm.HopLimit = i + 1
149 + if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
150 + t.Fatalf("ipv6.PacketConn.SetWriteDeadline failed: %v", err)
151 + }
152 + if n, err := p.WriteTo(wb, &cm, dst); err != nil {
153 + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
154 + } else if n != len(wb) {
155 + t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
156 + }
157 + rb := make([]byte, 128)
158 + if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
159 + t.Fatalf("ipv6.PacketConn.SetReadDeadline failed: %v", err)
160 + }
161 + if n, cm, _, err := p.ReadFrom(rb); err != nil {
162 + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
163 + } else {
164 + t.Logf("rcvd cmsg: %v", cm)
165 + if m, err := parseICMPMessage(rb[:n]); err != nil {
166 + t.Fatalf("parseICMPMessage failed: %v", err)
167 + } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
168 + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
169 + }
170 + }
171 + }
172 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/unicastsockopt_test.go new
+101
@@ -0,0 +1,101 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +package ipv6_test
6 +
7 +import (
8 + "code.google.com/p/go.net/ipv6"
9 + "net"
10 + "os"
11 + "runtime"
12 + "testing"
13 +)
14 +
15 +func TestConnUnicastSocketOptions(t *testing.T) {
16 + switch runtime.GOOS {
17 + case "plan9", "solaris", "windows":
18 + t.Skipf("not supported on %q", runtime.GOOS)
19 + }
20 + if !supportsIPv6 {
21 + t.Skip("ipv6 is not supported")
22 + }
23 +
24 + ln, err := net.Listen("tcp6", "[::1]:0")
25 + if err != nil {
26 + t.Fatalf("net.Listen failed: %v", err)
27 + }
28 + defer ln.Close()
29 +
30 + done := make(chan bool)
31 + go acceptor(t, ln, done)
32 +
33 + c, err := net.Dial("tcp6", ln.Addr().String())
34 + if err != nil {
35 + t.Fatalf("net.Dial failed: %v", err)
36 + }
37 + defer c.Close()
38 +
39 + testUnicastSocketOptions(t, ipv6.NewConn(c))
40 +
41 + <-done
42 +}
43 +
44 +var packetConnUnicastSocketOptionTests = []struct {
45 + net, proto, addr string
46 +}{
47 + {"udp6", "", "[::1]:0"},
48 + {"ip6", ":ipv6-icmp", "::1"},
49 +}
50 +
51 +func TestPacketConnUnicastSocketOptions(t *testing.T) {
52 + switch runtime.GOOS {
53 + case "plan9", "solaris", "windows":
54 + t.Skipf("not supported on %q", runtime.GOOS)
55 + }
56 + if !supportsIPv6 {
57 + t.Skip("ipv6 is not supported")
58 + }
59 +
60 + for _, tt := range packetConnUnicastSocketOptionTests {
61 + if tt.net == "ip6" && os.Getuid() != 0 {
62 + t.Skip("must be root")
63 + }
64 + c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
65 + if err != nil {
66 + t.Fatalf("net.ListenPacket(%q, %q) failed: %v", tt.net+tt.proto, tt.addr, err)
67 + }
68 + defer c.Close()
69 +
70 + testUnicastSocketOptions(t, ipv6.NewPacketConn(c))
71 + }
72 +}
73 +
74 +type testIPv6UnicastConn interface {
75 + TrafficClass() (int, error)
76 + SetTrafficClass(int) error
77 + HopLimit() (int, error)
78 + SetHopLimit(int) error
79 +}
80 +
81 +func testUnicastSocketOptions(t *testing.T, c testIPv6UnicastConn) {
82 + tclass := DiffServCS0 | NotECNTransport
83 + if err := c.SetTrafficClass(tclass); err != nil {
84 + t.Fatalf("ipv6.Conn.SetTrafficClass failed: %v", err)
85 + }
86 + if v, err := c.TrafficClass(); err != nil {
87 + t.Fatalf("ipv6.Conn.TrafficClass failed: %v", err)
88 + } else if v != tclass {
89 + t.Fatalf("got unexpected traffic class %v; expected %v", v, tclass)
90 + }
91 +
92 + hoplim := 255
93 + if err := c.SetHopLimit(hoplim); err != nil {
94 + t.Fatalf("ipv6.Conn.SetHopLimit failed: %v", err)
95 + }
96 + if v, err := c.HopLimit(); err != nil {
97 + t.Fatalf("ipv6.Conn.HopLimit failed: %v", err)
98 + } else if v != hoplim {
99 + t.Fatalf("got unexpected hop limit %v; expected %v", v, hoplim)
100 + }
101 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_darwin.go new
+101
@@ -0,0 +1,101 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_darwin.go
3 +
4 +package ipv6
5 +
6 +const (
7 + sysIPV6_UNICAST_HOPS = 0x4
8 + sysIPV6_MULTICAST_IF = 0x9
9 + sysIPV6_MULTICAST_HOPS = 0xa
10 + sysIPV6_MULTICAST_LOOP = 0xb
11 + sysIPV6_JOIN_GROUP = 0xc
12 + sysIPV6_LEAVE_GROUP = 0xd
13 +
14 + sysIPV6_PORTRANGE = 0xe
15 + sysICMP6_FILTER = 0x12
16 + sysIPV6_2292PKTINFO = 0x13
17 + sysIPV6_2292HOPLIMIT = 0x14
18 + sysIPV6_2292NEXTHOP = 0x15
19 + sysIPV6_2292HOPOPTS = 0x16
20 + sysIPV6_2292DSTOPTS = 0x17
21 + sysIPV6_2292RTHDR = 0x18
22 +
23 + sysIPV6_2292PKTOPTIONS = 0x19
24 +
25 + sysIPV6_CHECKSUM = 0x1a
26 + sysIPV6_V6ONLY = 0x1b
27 +
28 + sysIPV6_IPSEC_POLICY = 0x1c
29 +
30 + sysIPV6_RECVTCLASS = 0x23
31 + sysIPV6_TCLASS = 0x24
32 +
33 + sysIPV6_RTHDRDSTOPTS = 0x39
34 +
35 + sysIPV6_RECVPKTINFO = 0x3d
36 +
37 + sysIPV6_RECVHOPLIMIT = 0x25
38 + sysIPV6_RECVRTHDR = 0x26
39 + sysIPV6_RECVHOPOPTS = 0x27
40 + sysIPV6_RECVDSTOPTS = 0x28
41 +
42 + sysIPV6_USE_MIN_MTU = 0x2a
43 + sysIPV6_RECVPATHMTU = 0x2b
44 +
45 + sysIPV6_PATHMTU = 0x2c
46 +
47 + sysIPV6_PKTINFO = 0x2e
48 + sysIPV6_HOPLIMIT = 0x2f
49 + sysIPV6_NEXTHOP = 0x30
50 + sysIPV6_HOPOPTS = 0x31
51 + sysIPV6_DSTOPTS = 0x32
52 + sysIPV6_RTHDR = 0x33
53 +
54 + sysIPV6_AUTOFLOWLABEL = 0x3b
55 +
56 + sysIPV6_DONTFRAG = 0x3e
57 +
58 + sysIPV6_PREFER_TEMPADDR = 0x3f
59 +
60 + sysIPV6_BOUND_IF = 0x7d
61 +
62 + sysIPV6_PORTRANGE_DEFAULT = 0x0
63 + sysIPV6_PORTRANGE_HIGH = 0x1
64 + sysIPV6_PORTRANGE_LOW = 0x2
65 +
66 + sysSizeofSockaddrInet6 = 0x1c
67 + sysSizeofInet6Pktinfo = 0x14
68 + sysSizeofIPv6Mtuinfo = 0x20
69 +
70 + sysSizeofIPv6Mreq = 0x14
71 +
72 + sysSizeofICMPv6Filter = 0x20
73 +)
74 +
75 +type sysSockaddrInet6 struct {
76 + Len uint8
77 + Family uint8
78 + Port uint16
79 + Flowinfo uint32
80 + Addr [16]byte /* in6_addr */
81 + Scope_id uint32
82 +}
83 +
84 +type sysInet6Pktinfo struct {
85 + Addr [16]byte /* in6_addr */
86 + Ifindex uint32
87 +}
88 +
89 +type sysIPv6Mtuinfo struct {
90 + Addr sysSockaddrInet6
91 + Mtu uint32
92 +}
93 +
94 +type sysIPv6Mreq struct {
95 + Multiaddr [16]byte /* in6_addr */
96 + Interface uint32
97 +}
98 +
99 +type sysICMPv6Filter struct {
100 + Filt [8]uint32
101 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_dragonfly.go new
+90
@@ -0,0 +1,90 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_dragonfly.go
3 +
4 +// +build dragonfly
5 +
6 +package ipv6
7 +
8 +const (
9 + sysIPV6_UNICAST_HOPS = 0x4
10 + sysIPV6_MULTICAST_IF = 0x9
11 + sysIPV6_MULTICAST_HOPS = 0xa
12 + sysIPV6_MULTICAST_LOOP = 0xb
13 + sysIPV6_JOIN_GROUP = 0xc
14 + sysIPV6_LEAVE_GROUP = 0xd
15 + sysIPV6_PORTRANGE = 0xe
16 + sysICMP6_FILTER = 0x12
17 +
18 + sysIPV6_CHECKSUM = 0x1a
19 + sysIPV6_V6ONLY = 0x1b
20 +
21 + sysIPV6_IPSEC_POLICY = 0x1c
22 +
23 + sysIPV6_RTHDRDSTOPTS = 0x23
24 + sysIPV6_RECVPKTINFO = 0x24
25 + sysIPV6_RECVHOPLIMIT = 0x25
26 + sysIPV6_RECVRTHDR = 0x26
27 + sysIPV6_RECVHOPOPTS = 0x27
28 + sysIPV6_RECVDSTOPTS = 0x28
29 +
30 + sysIPV6_USE_MIN_MTU = 0x2a
31 + sysIPV6_RECVPATHMTU = 0x2b
32 +
33 + sysIPV6_PATHMTU = 0x2c
34 +
35 + sysIPV6_PKTINFO = 0x2e
36 + sysIPV6_HOPLIMIT = 0x2f
37 + sysIPV6_NEXTHOP = 0x30
38 + sysIPV6_HOPOPTS = 0x31
39 + sysIPV6_DSTOPTS = 0x32
40 + sysIPV6_RTHDR = 0x33
41 +
42 + sysIPV6_RECVTCLASS = 0x39
43 +
44 + sysIPV6_AUTOFLOWLABEL = 0x3b
45 +
46 + sysIPV6_TCLASS = 0x3d
47 + sysIPV6_DONTFRAG = 0x3e
48 +
49 + sysIPV6_PREFER_TEMPADDR = 0x3f
50 +
51 + sysIPV6_PORTRANGE_DEFAULT = 0x0
52 + sysIPV6_PORTRANGE_HIGH = 0x1
53 + sysIPV6_PORTRANGE_LOW = 0x2
54 +
55 + sysSizeofSockaddrInet6 = 0x1c
56 + sysSizeofInet6Pktinfo = 0x14
57 + sysSizeofIPv6Mtuinfo = 0x20
58 +
59 + sysSizeofIPv6Mreq = 0x14
60 +
61 + sysSizeofICMPv6Filter = 0x20
62 +)
63 +
64 +type sysSockaddrInet6 struct {
65 + Len uint8
66 + Family uint8
67 + Port uint16
68 + Flowinfo uint32
69 + Addr [16]byte /* in6_addr */
70 + Scope_id uint32
71 +}
72 +
73 +type sysInet6Pktinfo struct {
74 + Addr [16]byte /* in6_addr */
75 + Ifindex uint32
76 +}
77 +
78 +type sysIPv6Mtuinfo struct {
79 + Addr sysSockaddrInet6
80 + Mtu uint32
81 +}
82 +
83 +type sysIPv6Mreq struct {
84 + Multiaddr [16]byte /* in6_addr */
85 + Interface uint32
86 +}
87 +
88 +type sysICMPv6Filter struct {
89 + Filt [8]uint32
90 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_freebsd.go new
+91
@@ -0,0 +1,91 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_freebsd.go
3 +
4 +package ipv6
5 +
6 +const (
7 + sysIPV6_UNICAST_HOPS = 0x4
8 + sysIPV6_MULTICAST_IF = 0x9
9 + sysIPV6_MULTICAST_HOPS = 0xa
10 + sysIPV6_MULTICAST_LOOP = 0xb
11 + sysIPV6_JOIN_GROUP = 0xc
12 + sysIPV6_LEAVE_GROUP = 0xd
13 + sysIPV6_PORTRANGE = 0xe
14 + sysICMP6_FILTER = 0x12
15 +
16 + sysIPV6_CHECKSUM = 0x1a
17 + sysIPV6_V6ONLY = 0x1b
18 +
19 + sysIPV6_IPSEC_POLICY = 0x1c
20 +
21 + sysIPV6_RTHDRDSTOPTS = 0x23
22 +
23 + sysIPV6_RECVPKTINFO = 0x24
24 + sysIPV6_RECVHOPLIMIT = 0x25
25 + sysIPV6_RECVRTHDR = 0x26
26 + sysIPV6_RECVHOPOPTS = 0x27
27 + sysIPV6_RECVDSTOPTS = 0x28
28 +
29 + sysIPV6_USE_MIN_MTU = 0x2a
30 + sysIPV6_RECVPATHMTU = 0x2b
31 +
32 + sysIPV6_PATHMTU = 0x2c
33 +
34 + sysIPV6_PKTINFO = 0x2e
35 + sysIPV6_HOPLIMIT = 0x2f
36 + sysIPV6_NEXTHOP = 0x30
37 + sysIPV6_HOPOPTS = 0x31
38 + sysIPV6_DSTOPTS = 0x32
39 + sysIPV6_RTHDR = 0x33
40 +
41 + sysIPV6_RECVTCLASS = 0x39
42 +
43 + sysIPV6_AUTOFLOWLABEL = 0x3b
44 +
45 + sysIPV6_TCLASS = 0x3d
46 + sysIPV6_DONTFRAG = 0x3e
47 +
48 + sysIPV6_PREFER_TEMPADDR = 0x3f
49 +
50 + sysIPV6_BINDANY = 0x40
51 +
52 + sysIPV6_PORTRANGE_DEFAULT = 0x0
53 + sysIPV6_PORTRANGE_HIGH = 0x1
54 + sysIPV6_PORTRANGE_LOW = 0x2
55 +
56 + sysSizeofSockaddrInet6 = 0x1c
57 + sysSizeofInet6Pktinfo = 0x14
58 + sysSizeofIPv6Mtuinfo = 0x20
59 +
60 + sysSizeofIPv6Mreq = 0x14
61 +
62 + sysSizeofICMPv6Filter = 0x20
63 +)
64 +
65 +type sysSockaddrInet6 struct {
66 + Len uint8
67 + Family uint8
68 + Port uint16
69 + Flowinfo uint32
70 + Addr [16]byte /* in6_addr */
71 + Scope_id uint32
72 +}
73 +
74 +type sysInet6Pktinfo struct {
75 + Addr [16]byte /* in6_addr */
76 + Ifindex uint32
77 +}
78 +
79 +type sysIPv6Mtuinfo struct {
80 + Addr sysSockaddrInet6
81 + Mtu uint32
82 +}
83 +
84 +type sysIPv6Mreq struct {
85 + Multiaddr [16]byte /* in6_addr */
86 + Interface uint32
87 +}
88 +
89 +type sysICMPv6Filter struct {
90 + Filt [8]uint32
91 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_linux.go new
+133
@@ -0,0 +1,133 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_linux.go
3 +
4 +package ipv6
5 +
6 +const (
7 + sysIPV6_ADDRFORM = 0x1
8 + sysIPV6_2292PKTINFO = 0x2
9 + sysIPV6_2292HOPOPTS = 0x3
10 + sysIPV6_2292DSTOPTS = 0x4
11 + sysIPV6_2292RTHDR = 0x5
12 + sysIPV6_2292PKTOPTIONS = 0x6
13 + sysIPV6_CHECKSUM = 0x7
14 + sysIPV6_2292HOPLIMIT = 0x8
15 + sysIPV6_NEXTHOP = 0x9
16 + sysIPV6_FLOWINFO = 0xb
17 +
18 + sysIPV6_UNICAST_HOPS = 0x10
19 + sysIPV6_MULTICAST_IF = 0x11
20 + sysIPV6_MULTICAST_HOPS = 0x12
21 + sysIPV6_MULTICAST_LOOP = 0x13
22 + sysIPV6_ADD_MEMBERSHIP = 0x14
23 + sysIPV6_DROP_MEMBERSHIP = 0x15
24 + sysIPV6_ROUTER_ALERT = 0x16
25 + sysIPV6_MTU_DISCOVER = 0x17
26 + sysIPV6_MTU = 0x18
27 + sysIPV6_RECVERR = 0x19
28 + sysIPV6_V6ONLY = 0x1a
29 + sysIPV6_JOIN_ANYCAST = 0x1b
30 + sysIPV6_LEAVE_ANYCAST = 0x1c
31 +
32 + sysIPV6_PMTUDISC_DONT = 0x0
33 + sysIPV6_PMTUDISC_WANT = 0x1
34 + sysIPV6_PMTUDISC_DO = 0x2
35 + sysIPV6_PMTUDISC_PROBE = 0x3
36 + sysIPV6_PMTUDISC_INTERFACE = 0x4
37 + sysIPV6_PMTUDISC_OMIT = 0x5
38 +
39 + sysIPV6_FLOWLABEL_MGR = 0x20
40 + sysIPV6_FLOWINFO_SEND = 0x21
41 +
42 + sysIPV6_IPSEC_POLICY = 0x22
43 + sysIPV6_XFRM_POLICY = 0x23
44 +
45 + sysIPV6_RECVPKTINFO = 0x31
46 + sysIPV6_PKTINFO = 0x32
47 + sysIPV6_RECVHOPLIMIT = 0x33
48 + sysIPV6_HOPLIMIT = 0x34
49 + sysIPV6_RECVHOPOPTS = 0x35
50 + sysIPV6_HOPOPTS = 0x36
51 + sysIPV6_RTHDRDSTOPTS = 0x37
52 + sysIPV6_RECVRTHDR = 0x38
53 + sysIPV6_RTHDR = 0x39
54 + sysIPV6_RECVDSTOPTS = 0x3a
55 + sysIPV6_DSTOPTS = 0x3b
56 + sysIPV6_RECVPATHMTU = 0x3c
57 + sysIPV6_PATHMTU = 0x3d
58 + sysIPV6_DONTFRAG = 0x3e
59 +
60 + sysIPV6_RECVTCLASS = 0x42
61 + sysIPV6_TCLASS = 0x43
62 +
63 + sysIPV6_ADDR_PREFERENCES = 0x48
64 +
65 + sysIPV6_PREFER_SRC_TMP = 0x1
66 + sysIPV6_PREFER_SRC_PUBLIC = 0x2
67 + sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100
68 + sysIPV6_PREFER_SRC_COA = 0x4
69 + sysIPV6_PREFER_SRC_HOME = 0x400
70 + sysIPV6_PREFER_SRC_CGA = 0x8
71 + sysIPV6_PREFER_SRC_NONCGA = 0x800
72 +
73 + sysIPV6_MINHOPCOUNT = 0x49
74 +
75 + sysIPV6_ORIGDSTADDR = 0x4a
76 + sysIPV6_RECVORIGDSTADDR = 0x4a
77 + sysIPV6_TRANSPARENT = 0x4b
78 + sysIPV6_UNICAST_IF = 0x4c
79 +
80 + sysICMPV6_FILTER = 0x1
81 +
82 + sysICMPV6_FILTER_BLOCK = 0x1
83 + sysICMPV6_FILTER_PASS = 0x2
84 + sysICMPV6_FILTER_BLOCKOTHERS = 0x3
85 + sysICMPV6_FILTER_PASSONLY = 0x4
86 +
87 + sysSizeofSockaddrInet6 = 0x1c
88 + sysSizeofInet6Pktinfo = 0x14
89 + sysSizeofIPv6Mtuinfo = 0x20
90 + sysSizeofIPv6FlowlabelReq = 0x20
91 +
92 + sysSizeofIPv6Mreq = 0x14
93 +
94 + sysSizeofICMPv6Filter = 0x20
95 +)
96 +
97 +type sysSockaddrInet6 struct {
98 + Family uint16
99 + Port uint16
100 + Flowinfo uint32
101 + Addr [16]byte /* in6_addr */
102 + Scope_id uint32
103 +}
104 +
105 +type sysInet6Pktinfo struct {
106 + Addr [16]byte /* in6_addr */
107 + Ifindex int32
108 +}
109 +
110 +type sysIPv6Mtuinfo struct {
111 + Addr sysSockaddrInet6
112 + Mtu uint32
113 +}
114 +
115 +type sysIPv6FlowlabelReq struct {
116 + Dst [16]byte /* in6_addr */
117 + Label uint32
118 + Action uint8
119 + Share uint8
120 + Flags uint16
121 + Expires uint16
122 + Linger uint16
123 + X__flr_pad uint32
124 +}
125 +
126 +type sysIPv6Mreq struct {
127 + Multiaddr [16]byte /* in6_addr */
128 + Ifindex int32
129 +}
130 +
131 +type sysICMPv6Filter struct {
132 + Data [8]uint32
133 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_netbsd.go new
+84
@@ -0,0 +1,84 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_netbsd.go
3 +
4 +package ipv6
5 +
6 +const (
7 + sysIPV6_UNICAST_HOPS = 0x4
8 + sysIPV6_MULTICAST_IF = 0x9
9 + sysIPV6_MULTICAST_HOPS = 0xa
10 + sysIPV6_MULTICAST_LOOP = 0xb
11 + sysIPV6_JOIN_GROUP = 0xc
12 + sysIPV6_LEAVE_GROUP = 0xd
13 + sysIPV6_PORTRANGE = 0xe
14 + sysICMP6_FILTER = 0x12
15 +
16 + sysIPV6_CHECKSUM = 0x1a
17 + sysIPV6_V6ONLY = 0x1b
18 +
19 + sysIPV6_IPSEC_POLICY = 0x1c
20 +
21 + sysIPV6_RTHDRDSTOPTS = 0x23
22 +
23 + sysIPV6_RECVPKTINFO = 0x24
24 + sysIPV6_RECVHOPLIMIT = 0x25
25 + sysIPV6_RECVRTHDR = 0x26
26 + sysIPV6_RECVHOPOPTS = 0x27
27 + sysIPV6_RECVDSTOPTS = 0x28
28 +
29 + sysIPV6_USE_MIN_MTU = 0x2a
30 + sysIPV6_RECVPATHMTU = 0x2b
31 + sysIPV6_PATHMTU = 0x2c
32 +
33 + sysIPV6_PKTINFO = 0x2e
34 + sysIPV6_HOPLIMIT = 0x2f
35 + sysIPV6_NEXTHOP = 0x30
36 + sysIPV6_HOPOPTS = 0x31
37 + sysIPV6_DSTOPTS = 0x32
38 + sysIPV6_RTHDR = 0x33
39 +
40 + sysIPV6_RECVTCLASS = 0x39
41 +
42 + sysIPV6_TCLASS = 0x3d
43 + sysIPV6_DONTFRAG = 0x3e
44 +
45 + sysIPV6_PORTRANGE_DEFAULT = 0x0
46 + sysIPV6_PORTRANGE_HIGH = 0x1
47 + sysIPV6_PORTRANGE_LOW = 0x2
48 +
49 + sysSizeofSockaddrInet6 = 0x1c
50 + sysSizeofInet6Pktinfo = 0x14
51 + sysSizeofIPv6Mtuinfo = 0x20
52 +
53 + sysSizeofIPv6Mreq = 0x14
54 +
55 + sysSizeofICMPv6Filter = 0x20
56 +)
57 +
58 +type sysSockaddrInet6 struct {
59 + Len uint8
60 + Family uint8
61 + Port uint16
62 + Flowinfo uint32
63 + Addr [16]byte /* in6_addr */
64 + Scope_id uint32
65 +}
66 +
67 +type sysInet6Pktinfo struct {
68 + Addr [16]byte /* in6_addr */
69 + Ifindex uint32
70 +}
71 +
72 +type sysIPv6Mtuinfo struct {
73 + Addr sysSockaddrInet6
74 + Mtu uint32
75 +}
76 +
77 +type sysIPv6Mreq struct {
78 + Multiaddr [16]byte /* in6_addr */
79 + Interface uint32
80 +}
81 +
82 +type sysICMPv6Filter struct {
83 + Filt [8]uint32
84 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_openbsd.go new
+93
@@ -0,0 +1,93 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_openbsd.go
3 +
4 +package ipv6
5 +
6 +const (
7 + sysIPV6_UNICAST_HOPS = 0x4
8 + sysIPV6_MULTICAST_IF = 0x9
9 + sysIPV6_MULTICAST_HOPS = 0xa
10 + sysIPV6_MULTICAST_LOOP = 0xb
11 + sysIPV6_JOIN_GROUP = 0xc
12 + sysIPV6_LEAVE_GROUP = 0xd
13 + sysIPV6_PORTRANGE = 0xe
14 + sysICMP6_FILTER = 0x12
15 +
16 + sysIPV6_CHECKSUM = 0x1a
17 + sysIPV6_V6ONLY = 0x1b
18 +
19 + sysIPV6_RTHDRDSTOPTS = 0x23
20 +
21 + sysIPV6_RECVPKTINFO = 0x24
22 + sysIPV6_RECVHOPLIMIT = 0x25
23 + sysIPV6_RECVRTHDR = 0x26
24 + sysIPV6_RECVHOPOPTS = 0x27
25 + sysIPV6_RECVDSTOPTS = 0x28
26 +
27 + sysIPV6_USE_MIN_MTU = 0x2a
28 + sysIPV6_RECVPATHMTU = 0x2b
29 +
30 + sysIPV6_PATHMTU = 0x2c
31 +
32 + sysIPV6_PKTINFO = 0x2e
33 + sysIPV6_HOPLIMIT = 0x2f
34 + sysIPV6_NEXTHOP = 0x30
35 + sysIPV6_HOPOPTS = 0x31
36 + sysIPV6_DSTOPTS = 0x32
37 + sysIPV6_RTHDR = 0x33
38 +
39 + sysIPV6_AUTH_LEVEL = 0x35
40 + sysIPV6_ESP_TRANS_LEVEL = 0x36
41 + sysIPV6_ESP_NETWORK_LEVEL = 0x37
42 + sysIPSEC6_OUTSA = 0x38
43 + sysIPV6_RECVTCLASS = 0x39
44 +
45 + sysIPV6_AUTOFLOWLABEL = 0x3b
46 + sysIPV6_IPCOMP_LEVEL = 0x3c
47 +
48 + sysIPV6_TCLASS = 0x3d
49 + sysIPV6_DONTFRAG = 0x3e
50 + sysIPV6_PIPEX = 0x3f
51 +
52 + sysIPV6_RTABLE = 0x1021
53 +
54 + sysIPV6_PORTRANGE_DEFAULT = 0x0
55 + sysIPV6_PORTRANGE_HIGH = 0x1
56 + sysIPV6_PORTRANGE_LOW = 0x2
57 +
58 + sysSizeofSockaddrInet6 = 0x1c
59 + sysSizeofInet6Pktinfo = 0x14
60 + sysSizeofIPv6Mtuinfo = 0x20
61 +
62 + sysSizeofIPv6Mreq = 0x14
63 +
64 + sysSizeofICMPv6Filter = 0x20
65 +)
66 +
67 +type sysSockaddrInet6 struct {
68 + Len uint8
69 + Family uint8
70 + Port uint16
71 + Flowinfo uint32
72 + Addr [16]byte /* in6_addr */
73 + Scope_id uint32
74 +}
75 +
76 +type sysInet6Pktinfo struct {
77 + Addr [16]byte /* in6_addr */
78 + Ifindex uint32
79 +}
80 +
81 +type sysIPv6Mtuinfo struct {
82 + Addr sysSockaddrInet6
83 + Mtu uint32
84 +}
85 +
86 +type sysIPv6Mreq struct {
87 + Multiaddr [16]byte /* in6_addr */
88 + Interface uint32
89 +}
90 +
91 +type sysICMPv6Filter struct {
92 + Filt [8]uint32
93 +}
Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6/zsys_solaris.go new
+105
@@ -0,0 +1,105 @@
1 +// Created by cgo -godefs - DO NOT EDIT
2 +// cgo -godefs defs_solaris.go
3 +
4 +// +build solaris
5 +
6 +package ipv6
7 +
8 +const (
9 + sysIPV6_UNICAST_HOPS = 0x5
10 + sysIPV6_MULTICAST_IF = 0x6
11 + sysIPV6_MULTICAST_HOPS = 0x7
12 + sysIPV6_MULTICAST_LOOP = 0x8
13 + sysIPV6_JOIN_GROUP = 0x9
14 + sysIPV6_LEAVE_GROUP = 0xa
15 +
16 + sysIPV6_PKTINFO = 0xb
17 +
18 + sysIPV6_HOPLIMIT = 0xc
19 + sysIPV6_NEXTHOP = 0xd
20 + sysIPV6_HOPOPTS = 0xe
21 + sysIPV6_DSTOPTS = 0xf
22 +
23 + sysIPV6_RTHDR = 0x10
24 + sysIPV6_RTHDRDSTOPTS = 0x11
25 +
26 + sysIPV6_RECVPKTINFO = 0x12
27 + sysIPV6_RECVHOPLIMIT = 0x13
28 + sysIPV6_RECVHOPOPTS = 0x14
29 +
30 + sysIPV6_RECVRTHDR = 0x16
31 +
32 + sysIPV6_RECVRTHDRDSTOPTS = 0x17
33 +
34 + sysIPV6_CHECKSUM = 0x18
35 + sysIPV6_RECVTCLASS = 0x19
36 + sysIPV6_USE_MIN_MTU = 0x20
37 + sysIPV6_DONTFRAG = 0x21
38 + sysIPV6_SEC_OPT = 0x22
39 + sysIPV6_SRC_PREFERENCES = 0x23
40 + sysIPV6_RECVPATHMTU = 0x24
41 + sysIPV6_PATHMTU = 0x25
42 + sysIPV6_TCLASS = 0x26
43 + sysIPV6_V6ONLY = 0x27
44 +
45 + sysIPV6_RECVDSTOPTS = 0x28
46 +
47 + sysIPV6_PREFER_SRC_HOME = 0x1
48 + sysIPV6_PREFER_SRC_COA = 0x2
49 + sysIPV6_PREFER_SRC_PUBLIC = 0x4
50 + sysIPV6_PREFER_SRC_TMP = 0x8
51 + sysIPV6_PREFER_SRC_NONCGA = 0x10
52 + sysIPV6_PREFER_SRC_CGA = 0x20
53 +
54 + sysIPV6_PREFER_SRC_MIPMASK = 0x3
55 + sysIPV6_PREFER_SRC_MIPDEFAULT = 0x1
56 + sysIPV6_PREFER_SRC_TMPMASK = 0xc
57 + sysIPV6_PREFER_SRC_TMPDEFAULT = 0x4
58 + sysIPV6_PREFER_SRC_CGAMASK = 0x30
59 + sysIPV6_PREFER_SRC_CGADEFAULT = 0x10
60 +
61 + sysIPV6_PREFER_SRC_MASK = 0x3f
62 +
63 + sysIPV6_PREFER_SRC_DEFAULT = 0x15
64 +
65 + sysIPV6_BOUND_IF = 0x41
66 + sysIPV6_UNSPEC_SRC = 0x42
67 +
68 + sysICMP6_FILTER = 0x1
69 +
70 + sysSizeofSockaddrInet6 = 0x20
71 + sysSizeofInet6Pktinfo = 0x14
72 + sysSizeofIPv6Mtuinfo = 0x24
73 +
74 + sysSizeofIPv6Mreq = 0x14
75 +
76 + sysSizeofICMPv6Filter = 0x20
77 +)
78 +
79 +type sysSockaddrInet6 struct {
80 + Family uint16
81 + Port uint16
82 + Flowinfo uint32
83 + Addr [16]byte /* in6_addr */
84 + Scope_id uint32
85 + X__sin6_src_id uint32
86 +}
87 +
88 +type sysInet6Pktinfo struct {
89 + Addr [16]byte /* in6_addr */
90 + Ifindex uint32
91 +}
92 +
93 +type sysIPv6Mtuinfo struct {
94 + Addr sysSockaddrInet6
95 + Mtu uint32
96 +}
97 +
98 +type sysIPv6Mreq struct {
99 + Multiaddr [16]byte /* in6_addr */
100 + Interface uint32
101 +}
102 +
103 +type sysICMPv6Filter struct {
104 + X__icmp6_filt [8]uint32
105 +}
Godeps/_workspace/src/github.com/hashicorp/mdns/.gitignore new
+23
@@ -0,0 +1,23 @@
1 +# Compiled Object files, Static and Dynamic libs (Shared Objects)
2 +*.o
3 +*.a
4 +*.so
5 +
6 +# Folders
7 +_obj
8 +_test
9 +
10 +# Architecture specific extensions/prefixes
11 +*.[568vq]
12 +[568vq].out
13 +
14 +*.cgo1.go
15 +*.cgo2.c
16 +_cgo_defun.c
17 +_cgo_gotypes.go
18 +_cgo_export.*
19 +
20 +_testmain.go
21 +
22 +*.exe
23 +*.test
Godeps/_workspace/src/github.com/hashicorp/mdns/LICENSE new
+20
@@ -0,0 +1,20 @@
1 +The MIT License (MIT)
2 +
3 +Copyright (c) 2014 Armon Dadgar
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy of
6 +this software and associated documentation files (the "Software"), to deal in
7 +the Software without restriction, including without limitation the rights to
8 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 +the Software, and to permit persons to whom the Software is furnished to do so,
10 +subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Godeps/_workspace/src/github.com/hashicorp/mdns/README.md new
+37
@@ -0,0 +1,37 @@
1 +mdns
2 +====
3 +
4 +Simple mDNS client/server library in Golang. mDNS or Multicast DNS can be
5 +used to discover services on the local network without the use of an authoritative
6 +DNS server. This enables peer-to-peer discovery. It is important to note that many
7 +networks restrict the use of multicasting, which prevents mDNS from functioning.
8 +Notably, multicast cannot be used in any sort of cloud, or shared infrastructure
9 +environment. However it works well in most office, home, or private infrastructure
10 +environments.
11 +
12 +Using the library is very simple, here is an example of publishing a service entry:
13 +
14 + // Setup our service export
15 + host, _ := os.Hostname()
16 + info := []string{"My awesome service"},
17 + service, _ := NewMDNSService(host, "_foobar._tcp", "", "", 8000, nil, info)
18 +
19 + // Create the mDNS server, defer shutdown
20 + server, _ := mdns.NewServer(&mdns.Config{Zone: service})
21 + defer server.Shutdown()
22 +
23 +
24 +Doing a lookup for service providers is also very simple:
25 +
26 + // Make a channel for results and start listening
27 + entriesCh := make(chan *mdns.ServiceEntry, 4)
28 + go func() {
29 + for entry := range entriesCh {
30 + fmt.Printf("Got new entry: %v\n", entry)
31 + }
32 + }()
33 +
34 + // Start the lookup
35 + mdns.Lookup("_foobar._tcp", entriesCh)
36 + close(entriesCh)
37 +
Godeps/_workspace/src/github.com/hashicorp/mdns/client.go new
+362
@@ -0,0 +1,362 @@
1 +package mdns
2 +
3 +import (
4 + "fmt"
5 + "log"
6 + "net"
7 + "strings"
8 + "sync"
9 + "time"
10 +
11 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/go.net/ipv4"
12 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/go.net/ipv6"
13 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
14 +)
15 +
16 +// ServiceEntry is returned after we query for a service
17 +type ServiceEntry struct {
18 + Name string
19 + Host string
20 + AddrV4 net.IP
21 + AddrV6 net.IP
22 + Port int
23 + Info string
24 +
25 + Addr net.IP // @Deprecated
26 +
27 + hasTXT bool
28 + sent bool
29 +}
30 +
31 +// complete is used to check if we have all the info we need
32 +func (s *ServiceEntry) complete() bool {
33 + return (s.AddrV4 != nil || s.AddrV6 != nil || s.Addr != nil) && s.Port != 0 && s.hasTXT
34 +}
35 +
36 +// QueryParam is used to customize how a Lookup is performed
37 +type QueryParam struct {
38 + Service string // Service to lookup
39 + Domain string // Lookup domain, default "local"
40 + Timeout time.Duration // Lookup timeout, default 1 second
41 + Interface *net.Interface // Multicast interface to use
42 + Entries chan<- *ServiceEntry // Entries Channel
43 + WantUnicastResponse bool // Unicast response desired, as per 5.4 in RFC
44 +}
45 +
46 +// DefaultParams is used to return a default set of QueryParam's
47 +func DefaultParams(service string) *QueryParam {
48 + return &QueryParam{
49 + Service: service,
50 + Domain: "local",
51 + Timeout: time.Second,
52 + Entries: make(chan *ServiceEntry),
53 + WantUnicastResponse: false, // TODO(reddaly): Change this default.
54 + }
55 +}
56 +
57 +// Query looks up a given service, in a domain, waiting at most
58 +// for a timeout before finishing the query. The results are streamed
59 +// to a channel. Sends will not block, so clients should make sure to
60 +// either read or buffer.
61 +func Query(params *QueryParam) error {
62 + // Create a new client
63 + client, err := newClient()
64 + if err != nil {
65 + return err
66 + }
67 + defer client.Close()
68 +
69 + // Set the multicast interface
70 + if params.Interface != nil {
71 + if err := client.setInterface(params.Interface); err != nil {
72 + return err
73 + }
74 + }
75 +
76 + // Ensure defaults are set
77 + if params.Domain == "" {
78 + params.Domain = "local"
79 + }
80 + if params.Timeout == 0 {
81 + params.Timeout = time.Second
82 + }
83 +
84 + // Run the query
85 + return client.query(params)
86 +}
87 +
88 +// Lookup is the same as Query, however it uses all the default parameters
89 +func Lookup(service string, entries chan<- *ServiceEntry) error {
90 + params := DefaultParams(service)
91 + params.Entries = entries
92 + return Query(params)
93 +}
94 +
95 +// Client provides a query interface that can be used to
96 +// search for service providers using mDNS
97 +type client struct {
98 + ipv4UnicastConn *net.UDPConn
99 + ipv6UnicastConn *net.UDPConn
100 +
101 + ipv4MulticastConn *net.UDPConn
102 + ipv6MulticastConn *net.UDPConn
103 +
104 + closed bool
105 + closedCh chan struct{} // TODO(reddaly): This doesn't appear to be used.
106 + closeLock sync.Mutex
107 +}
108 +
109 +// NewClient creates a new mdns Client that can be used to query
110 +// for records
111 +func newClient() (*client, error) {
112 + // TODO(reddaly): At least attempt to bind to the port required in the spec.
113 + // Create a IPv4 listener
114 + uconn4, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
115 + if err != nil {
116 + log.Printf("[ERR] mdns: Failed to bind to udp4 port: %v", err)
117 + }
118 + uconn6, err := net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
119 + if err != nil {
120 + log.Printf("[ERR] mdns: Failed to bind to udp6 port: %v", err)
121 + }
122 +
123 + if uconn4 == nil && uconn6 == nil {
124 + return nil, fmt.Errorf("failed to bind to any unicast udp port")
125 + }
126 +
127 + mconn4, err := net.ListenMulticastUDP("udp4", nil, ipv4Addr)
128 + if err != nil {
129 + log.Printf("[ERR] mdns: Failed to bind to udp4 port: %v", err)
130 + }
131 + mconn6, err := net.ListenMulticastUDP("udp6", nil, ipv6Addr)
132 + if err != nil {
133 + log.Printf("[ERR] mdns: Failed to bind to udp6 port: %v", err)
134 + }
135 +
136 + if mconn4 == nil && mconn6 == nil {
137 + return nil, fmt.Errorf("failed to bind to any multicast udp port")
138 + }
139 +
140 + c := &client{
141 + ipv4MulticastConn: mconn4,
142 + ipv6MulticastConn: mconn6,
143 + ipv4UnicastConn: uconn4,
144 + ipv6UnicastConn: uconn6,
145 + closedCh: make(chan struct{}),
146 + }
147 + return c, nil
148 +}
149 +
150 +// Close is used to cleanup the client
151 +func (c *client) Close() error {
152 + c.closeLock.Lock()
153 + defer c.closeLock.Unlock()
154 +
155 + if c.closed {
156 + return nil
157 + }
158 + c.closed = true
159 +
160 + log.Printf("[INFO] mdns: Closing client %v", *c)
161 + close(c.closedCh)
162 +
163 + if c.ipv4UnicastConn != nil {
164 + c.ipv4UnicastConn.Close()
165 + }
166 + if c.ipv6UnicastConn != nil {
167 + c.ipv6UnicastConn.Close()
168 + }
169 + if c.ipv4MulticastConn != nil {
170 + c.ipv4MulticastConn.Close()
171 + }
172 + if c.ipv6MulticastConn != nil {
173 + c.ipv6MulticastConn.Close()
174 + }
175 +
176 + return nil
177 +}
178 +
179 +// setInterface is used to set the query interface, uses sytem
180 +// default if not provided
181 +func (c *client) setInterface(iface *net.Interface) error {
182 + p := ipv4.NewPacketConn(c.ipv4UnicastConn)
183 + if err := p.SetMulticastInterface(iface); err != nil {
184 + return err
185 + }
186 + p2 := ipv6.NewPacketConn(c.ipv6UnicastConn)
187 + if err := p2.SetMulticastInterface(iface); err != nil {
188 + return err
189 + }
190 + p = ipv4.NewPacketConn(c.ipv4MulticastConn)
191 + if err := p.SetMulticastInterface(iface); err != nil {
192 + return err
193 + }
194 + p2 = ipv6.NewPacketConn(c.ipv6MulticastConn)
195 + if err := p2.SetMulticastInterface(iface); err != nil {
196 + return err
197 + }
198 + return nil
199 +}
200 +
201 +// query is used to perform a lookup and stream results
202 +func (c *client) query(params *QueryParam) error {
203 + // Create the service name
204 + serviceAddr := fmt.Sprintf("%s.%s.", trimDot(params.Service), trimDot(params.Domain))
205 +
206 + // Start listening for response packets
207 + msgCh := make(chan *dns.Msg, 32)
208 + go c.recv(c.ipv4UnicastConn, msgCh)
209 + go c.recv(c.ipv6UnicastConn, msgCh)
210 + go c.recv(c.ipv4MulticastConn, msgCh)
211 + go c.recv(c.ipv6MulticastConn, msgCh)
212 +
213 + // Send the query
214 + m := new(dns.Msg)
215 + m.SetQuestion(serviceAddr, dns.TypePTR)
216 + // RFC 6762, section 18.12. Repurposing of Top Bit of qclass in Question
217 + // Section
218 + //
219 + // In the Question Section of a Multicast DNS query, the top bit of the qclass
220 + // field is used to indicate that unicast responses are preferred for this
221 + // particular question. (See Section 5.4.)
222 + if params.WantUnicastResponse {
223 + m.Question[0].Qclass |= 1 << 15
224 + }
225 + m.RecursionDesired = false
226 + if err := c.sendQuery(m); err != nil {
227 + return err
228 + }
229 +
230 + // Map the in-progress responses
231 + inprogress := make(map[string]*ServiceEntry)
232 +
233 + // Listen until we reach the timeout
234 + finish := time.After(params.Timeout)
235 + for {
236 + select {
237 + case resp := <-msgCh:
238 + var inp *ServiceEntry
239 + for _, answer := range resp.Answer {
240 + // TODO(reddaly): Check that response corresponds to serviceAddr?
241 + switch rr := answer.(type) {
242 + case *dns.PTR:
243 + // Create new entry for this
244 + inp = ensureName(inprogress, rr.Ptr)
245 +
246 + case *dns.SRV:
247 + // Check for a target mismatch
248 + if rr.Target != rr.Hdr.Name {
249 + alias(inprogress, rr.Hdr.Name, rr.Target)
250 + }
251 +
252 + // Get the port
253 + inp = ensureName(inprogress, rr.Hdr.Name)
254 + inp.Host = rr.Target
255 + inp.Port = int(rr.Port)
256 +
257 + case *dns.TXT:
258 + // Pull out the txt
259 + inp = ensureName(inprogress, rr.Hdr.Name)
260 + inp.Info = strings.Join(rr.Txt, "|")
261 + inp.hasTXT = true
262 +
263 + case *dns.A:
264 + // Pull out the IP
265 + inp = ensureName(inprogress, rr.Hdr.Name)
266 + inp.Addr = rr.A // @Deprecated
267 + inp.AddrV4 = rr.A
268 +
269 + case *dns.AAAA:
270 + // Pull out the IP
271 + inp = ensureName(inprogress, rr.Hdr.Name)
272 + inp.Addr = rr.AAAA // @Deprecated
273 + inp.AddrV6 = rr.AAAA
274 + }
275 + }
276 +
277 + if inp == nil {
278 + continue
279 + }
280 +
281 + // Check if this entry is complete
282 + if inp.complete() {
283 + if inp.sent {
284 + continue
285 + }
286 + inp.sent = true
287 + select {
288 + case params.Entries <- inp:
289 + default:
290 + }
291 + } else {
292 + // Fire off a node specific query
293 + m := new(dns.Msg)
294 + m.SetQuestion(inp.Name, dns.TypePTR)
295 + m.RecursionDesired = false
296 + if err := c.sendQuery(m); err != nil {
297 + log.Printf("[ERR] mdns: Failed to query instance %s: %v", inp.Name, err)
298 + }
299 + }
300 + case <-finish:
301 + return nil
302 + }
303 + }
304 +}
305 +
306 +// sendQuery is used to multicast a query out
307 +func (c *client) sendQuery(q *dns.Msg) error {
308 + buf, err := q.Pack()
309 + if err != nil {
310 + return err
311 + }
312 + if c.ipv4UnicastConn != nil {
313 + c.ipv4UnicastConn.WriteToUDP(buf, ipv4Addr)
314 + }
315 + if c.ipv6UnicastConn != nil {
316 + c.ipv6UnicastConn.WriteToUDP(buf, ipv6Addr)
317 + }
318 + return nil
319 +}
320 +
321 +// recv is used to receive until we get a shutdown
322 +func (c *client) recv(l *net.UDPConn, msgCh chan *dns.Msg) {
323 + if l == nil {
324 + return
325 + }
326 + buf := make([]byte, 65536)
327 + for !c.closed {
328 + n, err := l.Read(buf)
329 + if err != nil {
330 + log.Printf("[ERR] mdns: Failed to read packet: %v", err)
331 + continue
332 + }
333 + msg := new(dns.Msg)
334 + if err := msg.Unpack(buf[:n]); err != nil {
335 + log.Printf("[ERR] mdns: Failed to unpack packet: %v", err)
336 + continue
337 + }
338 + select {
339 + case msgCh <- msg:
340 + case <-c.closedCh:
341 + return
342 + }
343 + }
344 +}
345 +
346 +// ensureName is used to ensure the named node is in progress
347 +func ensureName(inprogress map[string]*ServiceEntry, name string) *ServiceEntry {
348 + if inp, ok := inprogress[name]; ok {
349 + return inp
350 + }
351 + inp := &ServiceEntry{
352 + Name: name,
353 + }
354 + inprogress[name] = inp
355 + return inp
356 +}
357 +
358 +// alias is used to setup an alias between two entries
359 +func alias(inprogress map[string]*ServiceEntry, src, dst string) {
360 + srcEntry := ensureName(inprogress, src)
361 + inprogress[dst] = srcEntry
362 +}
Godeps/_workspace/src/github.com/hashicorp/mdns/server.go new
+300
@@ -0,0 +1,300 @@
1 +package mdns
2 +
3 +import (
4 + "fmt"
5 + "log"
6 + "net"
7 + "strings"
8 + "sync"
9 +
10 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
11 +)
12 +
13 +const (
14 + ipv4mdns = "224.0.0.251"
15 + ipv6mdns = "ff02::fb"
16 + mdnsPort = 5353
17 + forceUnicastResponses = false
18 +)
19 +
20 +var (
21 + ipv4Addr = &net.UDPAddr{
22 + IP: net.ParseIP(ipv4mdns),
23 + Port: mdnsPort,
24 + }
25 + ipv6Addr = &net.UDPAddr{
26 + IP: net.ParseIP(ipv6mdns),
27 + Port: mdnsPort,
28 + }
29 +)
30 +
31 +// Config is used to configure the mDNS server
32 +type Config struct {
33 + // Zone must be provided to support responding to queries
34 + Zone Zone
35 +
36 + // Iface if provided binds the multicast listener to the given
37 + // interface. If not provided, the system default multicase interface
38 + // is used.
39 + Iface *net.Interface
40 +}
41 +
42 +// mDNS server is used to listen for mDNS queries and respond if we
43 +// have a matching local record
44 +type Server struct {
45 + config *Config
46 +
47 + ipv4List *net.UDPConn
48 + ipv6List *net.UDPConn
49 +
50 + shutdown bool
51 + shutdownCh chan struct{}
52 + shutdownLock sync.Mutex
53 +}
54 +
55 +// NewServer is used to create a new mDNS server from a config
56 +func NewServer(config *Config) (*Server, error) {
57 + // Create the listeners
58 + ipv4List, _ := net.ListenMulticastUDP("udp4", config.Iface, ipv4Addr)
59 + ipv6List, _ := net.ListenMulticastUDP("udp6", config.Iface, ipv6Addr)
60 +
61 + // Check if we have any listener
62 + if ipv4List == nil && ipv6List == nil {
63 + return nil, fmt.Errorf("No multicast listeners could be started")
64 + }
65 +
66 + s := &Server{
67 + config: config,
68 + ipv4List: ipv4List,
69 + ipv6List: ipv6List,
70 + shutdownCh: make(chan struct{}),
71 + }
72 +
73 + if ipv4List != nil {
74 + go s.recv(s.ipv4List)
75 + }
76 +
77 + if ipv6List != nil {
78 + go s.recv(s.ipv6List)
79 + }
80 +
81 + return s, nil
82 +}
83 +
84 +// Shutdown is used to shutdown the listener
85 +func (s *Server) Shutdown() error {
86 + s.shutdownLock.Lock()
87 + defer s.shutdownLock.Unlock()
88 +
89 + if s.shutdown {
90 + return nil
91 + }
92 + s.shutdown = true
93 + close(s.shutdownCh)
94 +
95 + if s.ipv4List != nil {
96 + s.ipv4List.Close()
97 + }
98 + if s.ipv6List != nil {
99 + s.ipv6List.Close()
100 + }
101 + return nil
102 +}
103 +
104 +// recv is a long running routine to receive packets from an interface
105 +func (s *Server) recv(c *net.UDPConn) {
106 + if c == nil {
107 + return
108 + }
109 + buf := make([]byte, 65536)
110 + for !s.shutdown {
111 + n, from, err := c.ReadFrom(buf)
112 + if err != nil {
113 + continue
114 + }
115 + if err := s.parsePacket(buf[:n], from); err != nil {
116 + log.Printf("[ERR] mdns: Failed to handle query: %v", err)
117 + }
118 + }
119 +}
120 +
121 +// parsePacket is used to parse an incoming packet
122 +func (s *Server) parsePacket(packet []byte, from net.Addr) error {
123 + var msg dns.Msg
124 + if err := msg.Unpack(packet); err != nil {
125 + log.Printf("[ERR] mdns: Failed to unpack packet: %v", err)
126 + return err
127 + }
128 + return s.handleQuery(&msg, from)
129 +}
130 +
131 +// handleQuery is used to handle an incoming query
132 +func (s *Server) handleQuery(query *dns.Msg, from net.Addr) error {
133 + if query.Opcode != dns.OpcodeQuery {
134 + // "In both multicast query and multicast response messages, the OPCODE MUST
135 + // be zero on transmission (only standard queries are currently supported
136 + // over multicast). Multicast DNS messages received with an OPCODE other
137 + // than zero MUST be silently ignored." Note: OpcodeQuery == 0
138 + return fmt.Errorf("mdns: received query with non-zero Opcode %v: %v", query.Opcode, *query)
139 + }
140 + if query.Rcode != 0 {
141 + // "In both multicast query and multicast response messages, the Response
142 + // Code MUST be zero on transmission. Multicast DNS messages received with
143 + // non-zero Response Codes MUST be silently ignored."
144 + return fmt.Errorf("mdns: received query with non-zero Rcode %v: %v", query.Rcode, *query)
145 + }
146 +
147 + // TODO(reddaly): Handle "TC (Truncated) Bit":
148 + // In query messages, if the TC bit is set, it means that additional
149 + // Known-Answer records may be following shortly. A responder SHOULD
150 + // record this fact, and wait for those additional Known-Answer records,
151 + // before deciding whether to respond. If the TC bit is clear, it means
152 + // that the querying host has no additional Known Answers.
153 + if query.Truncated {
154 + return fmt.Errorf("[ERR] mdns: support for DNS requests with high truncated bit not implemented: %v", *query)
155 + }
156 +
157 + var unicastAnswer, multicastAnswer []dns.RR
158 +
159 + // Handle each question
160 + for _, q := range query.Question {
161 + mrecs, urecs := s.handleQuestion(q)
162 + multicastAnswer = append(multicastAnswer, mrecs...)
163 + unicastAnswer = append(unicastAnswer, urecs...)
164 + }
165 +
166 + // See section 18 of RFC 6762 for rules about DNS headers.
167 + resp := func(unicast bool) *dns.Msg {
168 + // 18.1: ID (Query Identifier)
169 + // 0 for multicast response, query.Id for unicast response
170 + id := uint16(0)
171 + if unicast {
172 + id = query.Id
173 + }
174 +
175 + var answer []dns.RR
176 + if unicast {
177 + answer = unicastAnswer
178 + } else {
179 + answer = multicastAnswer
180 + }
181 + if len(answer) == 0 {
182 + return nil
183 + }
184 +
185 + return &dns.Msg{
186 + MsgHdr: dns.MsgHdr{
187 + Id: id,
188 +
189 + // 18.2: QR (Query/Response) Bit - must be set to 1 in response.
190 + Response: true,
191 +
192 + // 18.3: OPCODE - must be zero in response (OpcodeQuery == 0)
193 + Opcode: dns.OpcodeQuery,
194 +
195 + // 18.4: AA (Authoritative Answer) Bit - must be set to 1
196 + Authoritative: true,
197 +
198 + // The following fields must all be set to 0:
199 + // 18.5: TC (TRUNCATED) Bit
200 + // 18.6: RD (Recursion Desired) Bit
201 + // 18.7: RA (Recursion Available) Bit
202 + // 18.8: Z (Zero) Bit
203 + // 18.9: AD (Authentic Data) Bit
204 + // 18.10: CD (Checking Disabled) Bit
205 + // 18.11: RCODE (Response Code)
206 + },
207 + // 18.12 pertains to questions (handled by handleQuestion)
208 + // 18.13 pertains to resource records (handled by handleQuestion)
209 +
210 + // 18.14: Name Compression - responses should be compressed (though see
211 + // caveats in the RFC), so set the Compress bit (part of the dns library
212 + // API, not part of the DNS packet) to true.
213 + Compress: true,
214 +
215 + Answer: answer,
216 + }
217 + }
218 +
219 + if len(multicastAnswer) == 0 && len(unicastAnswer) == 0 {
220 + questions := make([]string, len(query.Question))
221 + for i, q := range query.Question {
222 + questions[i] = q.Name
223 + }
224 + log.Printf("no responses for query with questions: %s", strings.Join(questions, ", "))
225 + }
226 +
227 + if mresp := resp(false); mresp != nil {
228 + if err := s.sendResponse(mresp, from, false); err != nil {
229 + return fmt.Errorf("mdns: error sending multicast response: %v", err)
230 + }
231 + }
232 + if uresp := resp(true); uresp != nil {
233 + if err := s.sendResponse(uresp, from, true); err != nil {
234 + return fmt.Errorf("mdns: error sending unicast response: %v", err)
235 + }
236 + }
237 + return nil
238 +}
239 +
240 +// handleQuestion is used to handle an incoming question
241 +//
242 +// The response to a question may be transmitted over multicast, unicast, or
243 +// both. The return values are DNS records for each transmission type.
244 +func (s *Server) handleQuestion(q dns.Question) (multicastRecs, unicastRecs []dns.RR) {
245 + records := s.config.Zone.Records(q)
246 +
247 + if len(records) == 0 {
248 + return nil, nil
249 + }
250 +
251 + // Handle unicast and multicast responses.
252 + // TODO(reddaly): The decision about sending over unicast vs. multicast is not
253 + // yet fully compliant with RFC 6762. For example, the unicast bit should be
254 + // ignored if the records in question are close to TTL expiration. For now,
255 + // we just use the unicast bit to make the decision, as per the spec:
256 + // RFC 6762, section 18.12. Repurposing of Top Bit of qclass in Question
257 + // Section
258 + //
259 + // In the Question Section of a Multicast DNS query, the top bit of the
260 + // qclass field is used to indicate that unicast responses are preferred
261 + // for this particular question. (See Section 5.4.)
262 + if q.Qclass&(1<<15) != 0 || forceUnicastResponses {
263 + return nil, records
264 + }
265 + return records, nil
266 +}
267 +
268 +// sendResponse is used to send a response packet
269 +func (s *Server) sendResponse(resp *dns.Msg, from net.Addr, unicast bool) error {
270 + buf, err := resp.Pack()
271 + if err != nil {
272 + return err
273 + }
274 +
275 + // Determine the socket to send from
276 + addr := from.(*net.UDPAddr)
277 + var conn *net.UDPConn
278 + if addr.IP.To4() != nil {
279 + conn = s.ipv4List
280 + } else {
281 + conn = s.ipv6List
282 + }
283 +
284 + // Determine the address to send to if not unicast
285 + if !unicast {
286 + if addr.IP.To4() != nil {
287 + addr = ipv4Addr
288 + } else {
289 + addr = ipv6Addr
290 + }
291 + }
292 +
293 + // Guard against a missing connection or address
294 + if conn == nil || addr == nil {
295 + return fmt.Errorf("Unable to respond, missing connection (%v) or address (%v)",
296 + conn, addr)
297 + }
298 + _, err = conn.WriteToUDP(buf, addr)
299 + return err
300 +}
Godeps/_workspace/src/github.com/hashicorp/mdns/server_test.go new
+58
@@ -0,0 +1,58 @@
1 +package mdns
2 +
3 +import (
4 + "testing"
5 + "time"
6 +)
7 +
8 +func TestServer_StartStop(t *testing.T) {
9 + s := makeService(t)
10 + serv, err := NewServer(&Config{Zone: s})
11 + if err != nil {
12 + t.Fatalf("err: %v", err)
13 + }
14 + defer serv.Shutdown()
15 +}
16 +
17 +func TestServer_Lookup(t *testing.T) {
18 + serv, err := NewServer(&Config{Zone: makeServiceWithServiceName(t, "_foobar._tcp")})
19 + if err != nil {
20 + t.Fatalf("err: %v", err)
21 + }
22 + defer serv.Shutdown()
23 +
24 + entries := make(chan *ServiceEntry, 1)
25 + found := false
26 + go func() {
27 + select {
28 + case e := <-entries:
29 + if e.Name != "hostname._foobar._tcp.local." {
30 + t.Fatalf("bad: %v", e)
31 + }
32 + if e.Port != 80 {
33 + t.Fatalf("bad: %v", e)
34 + }
35 + if e.Info != "Local web server" {
36 + t.Fatalf("bad: %v", e)
37 + }
38 + found = true
39 +
40 + case <-time.After(80 * time.Millisecond):
41 + t.Fatalf("timeout")
42 + }
43 + }()
44 +
45 + params := &QueryParam{
46 + Service: "_foobar._tcp",
47 + Domain: "local",
48 + Timeout: 50 * time.Millisecond,
49 + Entries: entries,
50 + }
51 + err = Query(params)
52 + if err != nil {
53 + t.Fatalf("err: %v", err)
54 + }
55 + if !found {
56 + t.Fatalf("record not found")
57 + }
58 +}
Godeps/_workspace/src/github.com/hashicorp/mdns/zone.go new
+307
@@ -0,0 +1,307 @@
1 +package mdns
2 +
3 +import (
4 + "fmt"
5 + "net"
6 + "os"
7 + "strings"
8 +
9 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
10 +)
11 +
12 +const (
13 + // defaultTTL is the default TTL value in returned DNS records in seconds.
14 + defaultTTL = 120
15 +)
16 +
17 +// Zone is the interface used to integrate with the server and
18 +// to serve records dynamically
19 +type Zone interface {
20 + // Records returns DNS records in response to a DNS question.
21 + Records(q dns.Question) []dns.RR
22 +}
23 +
24 +// MDNSService is used to export a named service by implementing a Zone
25 +type MDNSService struct {
26 + Instance string // Instance name (e.g. "hostService name")
27 + Service string // Service name (e.g. "_http._tcp.")
28 + Domain string // If blank, assumes "local"
29 + HostName string // Host machine DNS name (e.g. "mymachine.net.")
30 + Port int // Service Port
31 + IPs []net.IP // IP addresses for the service's host
32 + TXT []string // Service TXT records
33 +
34 + serviceAddr string // Fully qualified service address
35 + instanceAddr string // Fully qualified instance address
36 + enumAddr string // _services._dns-sd._udp.<domain>
37 +}
38 +
39 +// validateFQDN returns an error if the passed string is not a fully qualified
40 +// hdomain name (more specifically, a hostname).
41 +func validateFQDN(s string) error {
42 + if len(s) == 0 {
43 + return fmt.Errorf("FQDN must not be blank")
44 + }
45 + if s[len(s)-1] != '.' {
46 + return fmt.Errorf("FQDN must end in period: %s", s)
47 + }
48 + // TODO(reddaly): Perform full validation.
49 +
50 + return nil
51 +}
52 +
53 +// NewMDNSService returns a new instance of MDNSService.
54 +//
55 +// If domain, hostName, or ips is set to the zero value, then a default value
56 +// will be inferred from the operating system.
57 +//
58 +// TODO(reddaly): This interface may need to change to account for "unique
59 +// record" conflict rules of the mDNS protocol. Upon startup, the server should
60 +// check to ensure that the instance name does not conflict with other instance
61 +// names, and, if required, select a new name. There may also be conflicting
62 +// hostName A/AAAA records.
63 +func NewMDNSService(instance, service, domain, hostName string, port int, ips []net.IP, txt []string) (*MDNSService, error) {
64 + // Sanity check inputs
65 + if instance == "" {
66 + return nil, fmt.Errorf("missing service instance name")
67 + }
68 + if service == "" {
69 + return nil, fmt.Errorf("missing service name")
70 + }
71 + if port == 0 {
72 + return nil, fmt.Errorf("missing service port")
73 + }
74 +
75 + // Set default domain
76 + if domain == "" {
77 + domain = "local."
78 + }
79 + if err := validateFQDN(domain); err != nil {
80 + return nil, fmt.Errorf("domain %q is not a fully-qualified domain name: %v", domain, err)
81 + }
82 +
83 + // Get host information if no host is specified.
84 + if hostName == "" {
85 + var err error
86 + hostName, err = os.Hostname()
87 + if err != nil {
88 + return nil, fmt.Errorf("could not determine host: %v", err)
89 + }
90 + hostName = fmt.Sprintf("%s.", hostName)
91 + }
92 + if err := validateFQDN(hostName); err != nil {
93 + return nil, fmt.Errorf("hostName %q is not a fully-qualified domain name: %v", hostName, err)
94 + }
95 +
96 + if len(ips) == 0 {
97 + var err error
98 + ips, err = net.LookupIP(hostName)
99 + if err != nil {
100 + // Try appending the host domain suffix and lookup again
101 + // (required for Linux-based hosts)
102 + tmpHostName := fmt.Sprintf("%s%s.", hostName, domain)
103 +
104 + ips, err = net.LookupIP(tmpHostName)
105 +
106 + if err != nil {
107 + return nil, fmt.Errorf("could not determine host IP addresses for %s", hostName)
108 + }
109 + }
110 + }
111 + for _, ip := range ips {
112 + if ip.To4() == nil && ip.To16() == nil {
113 + return nil, fmt.Errorf("invalid IP address in IPs list: %v", ip)
114 + }
115 + }
116 +
117 + return &MDNSService{
118 + Instance: instance,
119 + Service: service,
120 + Domain: domain,
121 + HostName: hostName,
122 + Port: port,
123 + IPs: ips,
124 + TXT: txt,
125 + serviceAddr: fmt.Sprintf("%s.%s.", trimDot(service), trimDot(domain)),
126 + instanceAddr: fmt.Sprintf("%s.%s.%s.", instance, trimDot(service), trimDot(domain)),
127 + enumAddr: fmt.Sprintf("_services._dns-sd._udp.%s.", trimDot(domain)),
128 + }, nil
129 +}
130 +
131 +// trimDot is used to trim the dots from the start or end of a string
132 +func trimDot(s string) string {
133 + return strings.Trim(s, ".")
134 +}
135 +
136 +// Records returns DNS records in response to a DNS question.
137 +func (m *MDNSService) Records(q dns.Question) []dns.RR {
138 + switch q.Name {
139 + case m.enumAddr:
140 + return m.serviceEnum(q)
141 + case m.serviceAddr:
142 + return m.serviceRecords(q)
143 + case m.instanceAddr:
144 + return m.instanceRecords(q)
145 + case m.HostName:
146 + if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA {
147 + return m.instanceRecords(q)
148 + }
149 + fallthrough
150 + default:
151 + return nil
152 + }
153 +}
154 +
155 +func (m *MDNSService) serviceEnum(q dns.Question) []dns.RR {
156 + switch q.Qtype {
157 + case dns.TypeANY:
158 + fallthrough
159 + case dns.TypePTR:
160 + rr := &dns.PTR{
161 + Hdr: dns.RR_Header{
162 + Name: q.Name,
163 + Rrtype: dns.TypePTR,
164 + Class: dns.ClassINET,
165 + Ttl: defaultTTL,
166 + },
167 + Ptr: m.serviceAddr,
168 + }
169 + return []dns.RR{rr}
170 + default:
171 + return nil
172 + }
173 +}
174 +
175 +// serviceRecords is called when the query matches the service name
176 +func (m *MDNSService) serviceRecords(q dns.Question) []dns.RR {
177 + switch q.Qtype {
178 + case dns.TypeANY:
179 + fallthrough
180 + case dns.TypePTR:
181 + // Build a PTR response for the service
182 + rr := &dns.PTR{
183 + Hdr: dns.RR_Header{
184 + Name: q.Name,
185 + Rrtype: dns.TypePTR,
186 + Class: dns.ClassINET,
187 + Ttl: defaultTTL,
188 + },
189 + Ptr: m.instanceAddr,
190 + }
191 + servRec := []dns.RR{rr}
192 +
193 + // Get the instance records
194 + instRecs := m.instanceRecords(dns.Question{
195 + Name: m.instanceAddr,
196 + Qtype: dns.TypeANY,
197 + })
198 +
199 + // Return the service record with the instance records
200 + return append(servRec, instRecs...)
201 + default:
202 + return nil
203 + }
204 +}
205 +
206 +// serviceRecords is called when the query matches the instance name
207 +func (m *MDNSService) instanceRecords(q dns.Question) []dns.RR {
208 + switch q.Qtype {
209 + case dns.TypeANY:
210 + // Get the SRV, which includes A and AAAA
211 + recs := m.instanceRecords(dns.Question{
212 + Name: m.instanceAddr,
213 + Qtype: dns.TypeSRV,
214 + })
215 +
216 + // Add the TXT record
217 + recs = append(recs, m.instanceRecords(dns.Question{
218 + Name: m.instanceAddr,
219 + Qtype: dns.TypeTXT,
220 + })...)
221 + return recs
222 +
223 + case dns.TypeA:
224 + var rr []dns.RR
225 + for _, ip := range m.IPs {
226 + if ip4 := ip.To4(); ip4 != nil {
227 + rr = append(rr, &dns.A{
228 + Hdr: dns.RR_Header{
229 + Name: m.HostName,
230 + Rrtype: dns.TypeA,
231 + Class: dns.ClassINET,
232 + Ttl: defaultTTL,
233 + },
234 + A: ip4,
235 + })
236 + }
237 + }
238 + return rr
239 +
240 + case dns.TypeAAAA:
241 + var rr []dns.RR
242 + for _, ip := range m.IPs {
243 + if ip.To4() != nil {
244 + // TODO(reddaly): IPv4 addresses could be encoded in IPv6 format and
245 + // putinto AAAA records, but the current logic puts ipv4-encodable
246 + // addresses into the A records exclusively. Perhaps this should be
247 + // configurable?
248 + continue
249 + }
250 +
251 + if ip16 := ip.To16(); ip16 != nil {
252 + rr = append(rr, &dns.AAAA{
253 + Hdr: dns.RR_Header{
254 + Name: m.HostName,
255 + Rrtype: dns.TypeAAAA,
256 + Class: dns.ClassINET,
257 + Ttl: defaultTTL,
258 + },
259 + AAAA: ip16,
260 + })
261 + }
262 + }
263 + return rr
264 +
265 + case dns.TypeSRV:
266 + // Create the SRV Record
267 + srv := &dns.SRV{
268 + Hdr: dns.RR_Header{
269 + Name: q.Name,
270 + Rrtype: dns.TypeSRV,
271 + Class: dns.ClassINET,
272 + Ttl: defaultTTL,
273 + },
274 + Priority: 10,
275 + Weight: 1,
276 + Port: uint16(m.Port),
277 + Target: m.HostName,
278 + }
279 + recs := []dns.RR{srv}
280 +
281 + // Add the A record
282 + recs = append(recs, m.instanceRecords(dns.Question{
283 + Name: m.instanceAddr,
284 + Qtype: dns.TypeA,
285 + })...)
286 +
287 + // Add the AAAA record
288 + recs = append(recs, m.instanceRecords(dns.Question{
289 + Name: m.instanceAddr,
290 + Qtype: dns.TypeAAAA,
291 + })...)
292 + return recs
293 +
294 + case dns.TypeTXT:
295 + txt := &dns.TXT{
296 + Hdr: dns.RR_Header{
297 + Name: q.Name,
298 + Rrtype: dns.TypeTXT,
299 + Class: dns.ClassINET,
300 + Ttl: defaultTTL,
301 + },
302 + Txt: m.TXT,
303 + }
304 + return []dns.RR{txt}
305 + }
306 + return nil
307 +}
Godeps/_workspace/src/github.com/hashicorp/mdns/zone_test.go new
+275
@@ -0,0 +1,275 @@
1 +package mdns
2 +
3 +import (
4 + "bytes"
5 + "net"
6 + "reflect"
7 + "testing"
8 +
9 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
10 +)
11 +
12 +func makeService(t *testing.T) *MDNSService {
13 + return makeServiceWithServiceName(t, "_http._tcp")
14 +}
15 +
16 +func makeServiceWithServiceName(t *testing.T, service string) *MDNSService {
17 + m, err := NewMDNSService(
18 + "hostname",
19 + service,
20 + "local.",
21 + "testhost.",
22 + 80, // port
23 + []net.IP{net.IP([]byte{192, 168, 0, 42}), net.ParseIP("2620:0:1000:1900:b0c2:d0b2:c411:18bc")},
24 + []string{"Local web server"}) // TXT
25 +
26 + if err != nil {
27 + t.Fatalf("err: %v", err)
28 + }
29 +
30 + return m
31 +}
32 +
33 +func TestNewMDNSService_BadParams(t *testing.T) {
34 + for _, test := range []struct {
35 + testName string
36 + hostName string
37 + domain string
38 + }{
39 + {
40 + "NewMDNSService should fail when passed hostName that is not a legal fully-qualified domain name",
41 + "hostname", // not legal FQDN - should be "hostname." or "hostname.local.", etc.
42 + "local.", // legal
43 + },
44 + {
45 + "NewMDNSService should fail when passed domain that is not a legal fully-qualified domain name",
46 + "hostname.", // legal
47 + "local", // should be "local."
48 + },
49 + } {
50 + _, err := NewMDNSService(
51 + "instance name",
52 + "_http._tcp",
53 + test.domain,
54 + test.hostName,
55 + 80, // port
56 + []net.IP{net.IP([]byte{192, 168, 0, 42})},
57 + []string{"Local web server"}) // TXT
58 + if err == nil {
59 + t.Fatalf("%s: error expected, but got none", test.testName)
60 + }
61 + }
62 +}
63 +
64 +func TestMDNSService_BadAddr(t *testing.T) {
65 + s := makeService(t)
66 + q := dns.Question{
67 + Name: "random",
68 + Qtype: dns.TypeANY,
69 + }
70 + recs := s.Records(q)
71 + if len(recs) != 0 {
72 + t.Fatalf("bad: %v", recs)
73 + }
74 +}
75 +
76 +func TestMDNSService_ServiceAddr(t *testing.T) {
77 + s := makeService(t)
78 + q := dns.Question{
79 + Name: "_http._tcp.local.",
80 + Qtype: dns.TypeANY,
81 + }
82 + recs := s.Records(q)
83 + if got, want := len(recs), 5; got != want {
84 + t.Fatalf("got %d records, want %d: %v", got, want, recs)
85 + }
86 +
87 + if ptr, ok := recs[0].(*dns.PTR); !ok {
88 + t.Errorf("recs[0] should be PTR record, got: %v, all records: %v", recs[0], recs)
89 + } else if got, want := ptr.Ptr, "hostname._http._tcp.local."; got != want {
90 + t.Fatalf("bad PTR record %v: got %v, want %v", ptr, got, want)
91 + }
92 +
93 + if _, ok := recs[1].(*dns.SRV); !ok {
94 + t.Errorf("recs[1] should be SRV record, got: %v, all reccords: %v", recs[1], recs)
95 + }
96 + if _, ok := recs[2].(*dns.A); !ok {
97 + t.Errorf("recs[2] should be A record, got: %v, all records: %v", recs[2], recs)
98 + }
99 + if _, ok := recs[3].(*dns.AAAA); !ok {
100 + t.Errorf("recs[3] should be AAAA record, got: %v, all records: %v", recs[3], recs)
101 + }
102 + if _, ok := recs[4].(*dns.TXT); !ok {
103 + t.Errorf("recs[4] should be TXT record, got: %v, all records: %v", recs[4], recs)
104 + }
105 +
106 + q.Qtype = dns.TypePTR
107 + if recs2 := s.Records(q); !reflect.DeepEqual(recs, recs2) {
108 + t.Fatalf("PTR question should return same result as ANY question: ANY => %v, PTR => %v", recs, recs2)
109 + }
110 +}
111 +
112 +func TestMDNSService_InstanceAddr_ANY(t *testing.T) {
113 + s := makeService(t)
114 + q := dns.Question{
115 + Name: "hostname._http._tcp.local.",
116 + Qtype: dns.TypeANY,
117 + }
118 + recs := s.Records(q)
119 + if len(recs) != 4 {
120 + t.Fatalf("bad: %v", recs)
121 + }
122 + if _, ok := recs[0].(*dns.SRV); !ok {
123 + t.Fatalf("bad: %v", recs[0])
124 + }
125 + if _, ok := recs[1].(*dns.A); !ok {
126 + t.Fatalf("bad: %v", recs[1])
127 + }
128 + if _, ok := recs[2].(*dns.AAAA); !ok {
129 + t.Fatalf("bad: %v", recs[2])
130 + }
131 + if _, ok := recs[3].(*dns.TXT); !ok {
132 + t.Fatalf("bad: %v", recs[3])
133 + }
134 +}
135 +
136 +func TestMDNSService_InstanceAddr_SRV(t *testing.T) {
137 + s := makeService(t)
138 + q := dns.Question{
139 + Name: "hostname._http._tcp.local.",
140 + Qtype: dns.TypeSRV,
141 + }
142 + recs := s.Records(q)
143 + if len(recs) != 3 {
144 + t.Fatalf("bad: %v", recs)
145 + }
146 + srv, ok := recs[0].(*dns.SRV)
147 + if !ok {
148 + t.Fatalf("bad: %v", recs[0])
149 + }
150 + if _, ok := recs[1].(*dns.A); !ok {
151 + t.Fatalf("bad: %v", recs[1])
152 + }
153 + if _, ok := recs[2].(*dns.AAAA); !ok {
154 + t.Fatalf("bad: %v", recs[2])
155 + }
156 +
157 + if srv.Port != uint16(s.Port) {
158 + t.Fatalf("bad: %v", recs[0])
159 + }
160 +}
161 +
162 +func TestMDNSService_InstanceAddr_A(t *testing.T) {
163 + s := makeService(t)
164 + q := dns.Question{
165 + Name: "hostname._http._tcp.local.",
166 + Qtype: dns.TypeA,
167 + }
168 + recs := s.Records(q)
169 + if len(recs) != 1 {
170 + t.Fatalf("bad: %v", recs)
171 + }
172 + a, ok := recs[0].(*dns.A)
173 + if !ok {
174 + t.Fatalf("bad: %v", recs[0])
175 + }
176 + if !bytes.Equal(a.A, []byte{192, 168, 0, 42}) {
177 + t.Fatalf("bad: %v", recs[0])
178 + }
179 +}
180 +
181 +func TestMDNSService_InstanceAddr_AAAA(t *testing.T) {
182 + s := makeService(t)
183 + q := dns.Question{
184 + Name: "hostname._http._tcp.local.",
185 + Qtype: dns.TypeAAAA,
186 + }
187 + recs := s.Records(q)
188 + if len(recs) != 1 {
189 + t.Fatalf("bad: %v", recs)
190 + }
191 + a4, ok := recs[0].(*dns.AAAA)
192 + if !ok {
193 + t.Fatalf("bad: %v", recs[0])
194 + }
195 + ip6 := net.ParseIP("2620:0:1000:1900:b0c2:d0b2:c411:18bc")
196 + if got := len(ip6); got != net.IPv6len {
197 + t.Fatalf("test IP failed to parse (len = %d, want %d)", got, net.IPv6len)
198 + }
199 + if !bytes.Equal(a4.AAAA, ip6) {
200 + t.Fatalf("bad: %v", recs[0])
201 + }
202 +}
203 +
204 +func TestMDNSService_InstanceAddr_TXT(t *testing.T) {
205 + s := makeService(t)
206 + q := dns.Question{
207 + Name: "hostname._http._tcp.local.",
208 + Qtype: dns.TypeTXT,
209 + }
210 + recs := s.Records(q)
211 + if len(recs) != 1 {
212 + t.Fatalf("bad: %v", recs)
213 + }
214 + txt, ok := recs[0].(*dns.TXT)
215 + if !ok {
216 + t.Fatalf("bad: %v", recs[0])
217 + }
218 + if got, want := txt.Txt, s.TXT; !reflect.DeepEqual(got, want) {
219 + t.Fatalf("TXT record mismatch for %v: got %v, want %v", recs[0], got, want)
220 + }
221 +}
222 +
223 +func TestMDNSService_HostNameQuery(t *testing.T) {
224 + s := makeService(t)
225 + for _, test := range []struct {
226 + q dns.Question
227 + want []dns.RR
228 + }{
229 + {
230 + dns.Question{Name: "testhost.", Qtype: dns.TypeA},
231 + []dns.RR{&dns.A{
232 + Hdr: dns.RR_Header{
233 + Name: "testhost.",
234 + Rrtype: dns.TypeA,
235 + Class: dns.ClassINET,
236 + Ttl: 120,
237 + },
238 + A: net.IP([]byte{192, 168, 0, 42}),
239 + }},
240 + },
241 + {
242 + dns.Question{Name: "testhost.", Qtype: dns.TypeAAAA},
243 + []dns.RR{&dns.AAAA{
244 + Hdr: dns.RR_Header{
245 + Name: "testhost.",
246 + Rrtype: dns.TypeAAAA,
247 + Class: dns.ClassINET,
248 + Ttl: 120,
249 + },
250 + AAAA: net.ParseIP("2620:0:1000:1900:b0c2:d0b2:c411:18bc"),
251 + }},
252 + },
253 + } {
254 + if got := s.Records(test.q); !reflect.DeepEqual(got, test.want) {
255 + t.Errorf("hostname query failed: s.Records(%v) = %v, want %v", test.q, got, test.want)
256 + }
257 + }
258 +}
259 +
260 +func TestMDNSService_serviceEnum_PTR(t *testing.T) {
261 + s := makeService(t)
262 + q := dns.Question{
263 + Name: "_services._dns-sd._udp.local.",
264 + Qtype: dns.TypePTR,
265 + }
266 + recs := s.Records(q)
267 + if len(recs) != 1 {
268 + t.Fatalf("bad: %v", recs)
269 + }
270 + if ptr, ok := recs[0].(*dns.PTR); !ok {
271 + t.Errorf("recs[0] should be PTR record, got: %v, all records: %v", recs[0], recs)
272 + } else if got, want := ptr.Ptr, "_http._tcp.local."; got != want {
273 + t.Fatalf("bad PTR record %v: got %v, want %v", ptr, got, want)
274 + }
275 +}
Godeps/_workspace/src/github.com/miekg/dns/.gitignore new
+4
@@ -0,0 +1,4 @@
1 +*.6
2 +tags
3 +test.out
4 +a.out
Godeps/_workspace/src/github.com/miekg/dns/.travis.yml new
+21
@@ -0,0 +1,21 @@
1 +language: go
2 +go:
3 + - 1.2
4 + - 1.3
5 +env:
6 + # "gvm update" resets GOOS and GOARCH environment variable, workaround it by setting
7 + # BUILD_GOOS and BUILD_GOARCH and overriding GOARCH and GOOS in the build script
8 + global:
9 + - BUILD_GOARCH=amd64
10 + matrix:
11 + - BUILD_GOOS=linux
12 + - BUILD_GOOS=darwin
13 + - BUILD_GOOS=windows
14 +script:
15 + - gvm cross $BUILD_GOOS $BUILD_GOARCH
16 + - GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go build
17 +
18 + # only test on linux
19 + # also specify -short; the crypto tests fail in weird ways *sometimes*
20 + # See issue #151
21 + - if [ $BUILD_GOOS == "linux" ]; then GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go test -short -bench=.; fi
Godeps/_workspace/src/github.com/miekg/dns/AUTHORS new
+1
@@ -0,0 +1 @@
1 +Miek Gieben <miek@miek.nl>
Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS new
+9
@@ -0,0 +1,9 @@
1 +Alex A. Skinner
2 +Andrew Tunnell-Jones
3 +Ask Bjørn Hansen
4 +Dave Cheney
5 +Dusty Wilson
6 +Marek Majkowski
7 +Peter van Dijk
8 +Omri Bahumi
9 +Alex Sergeyev
Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT new
+9
@@ -0,0 +1,9 @@
1 +Copyright 2009 The Go Authors. All rights reserved. Use of this source code
2 +is governed by a BSD-style license that can be found in the LICENSE file.
3 +Extensions of the original work are copyright (c) 2011 Miek Gieben
4 +
5 +Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is
6 +governed by a BSD-style license that can be found in the LICENSE file.
7 +
8 +Copyright 2014 CloudFlare. All rights reserved. Use of this source code is
9 +governed by a BSD-style license that can be found in the LICENSE file.
Godeps/_workspace/src/github.com/miekg/dns/LICENSE new
+32
@@ -0,0 +1,32 @@
1 +Extensions of the original work are copyright (c) 2011 Miek Gieben
2 +
3 +As this is fork of the official Go code the same license applies:
4 +
5 +Copyright (c) 2009 The Go Authors. All rights reserved.
6 +
7 +Redistribution and use in source and binary forms, with or without
8 +modification, are permitted provided that the following conditions are
9 +met:
10 +
11 + * Redistributions of source code must retain the above copyright
12 +notice, this list of conditions and the following disclaimer.
13 + * Redistributions in binary form must reproduce the above
14 +copyright notice, this list of conditions and the following disclaimer
15 +in the documentation and/or other materials provided with the
16 +distribution.
17 + * Neither the name of Google Inc. nor the names of its
18 +contributors may be used to endorse or promote products derived from
19 +this software without specific prior written permission.
20 +
21 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 +
Godeps/_workspace/src/github.com/miekg/dns/README.md new
+141
@@ -0,0 +1,141 @@
1 +[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
2 +
3 +# Alternative (more granular) approach to a DNS library
4 +
5 +> Less is more.
6 +
7 +Complete and usable DNS library. All widely used Resource Records are
8 +supported, including the DNSSEC types. It follows a lean and mean philosophy.
9 +If there is stuff you should know as a DNS programmer there isn't a convenience
10 +function for it. Server side and client side programming is supported, i.e. you
11 +can build servers and resolvers with it.
12 +
13 +If you like this, you may also be interested in:
14 +
15 +* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver.
16 +
17 +# Goals
18 +
19 +* KISS;
20 +* Fast;
21 +* Small API, if its easy to code in Go, don't make a function for it.
22 +
23 +# Users
24 +
25 +A not-so-up-to-date-list-that-may-be-actually-current:
26 +
27 +* https://github.com/abh/geodns
28 +* http://www.statdns.com/
29 +* http://www.dnsinspect.com/
30 +* https://github.com/chuangbo/jianbing-dictionary-dns
31 +* http://www.dns-lg.com/
32 +* https://github.com/fcambus/rrda
33 +* https://github.com/kenshinx/godns
34 +* https://github.com/skynetservices/skydns
35 +* https://github.com/DevelopersPL/godnsagent
36 +* https://github.com/duedil-ltd/discodns
37 +* https://github.com/StalkR/dns-reverse-proxy
38 +
39 +Send pull request if you want to be listed here.
40 +
41 +# Features
42 +
43 +* UDP/TCP queries, IPv4 and IPv6;
44 +* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported;
45 +* Fast:
46 + * Reply speed around ~ 80K qps (faster hardware results in more qps);
47 + * Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds;
48 +* Server side programming (mimicking the net/http package);
49 +* Client side programming;
50 +* DNSSEC: signing, validating and key generation for DSA, RSA and ECDSA;
51 +* EDNS0, NSID;
52 +* AXFR/IXFR;
53 +* TSIG, SIG(0);
54 +* DNS name compression;
55 +* Depends only on the standard library.
56 +
57 +Have fun!
58 +
59 +Miek Gieben - 2010-2012 - <miek@miek.nl>
60 +
61 +# Building
62 +
63 +Building is done with the `go` tool. If you have setup your GOPATH
64 +correctly, the following should work:
65 +
66 + go get github.com/miekg/dns
67 + go build github.com/miekg/dns
68 +
69 +## Examples
70 +
71 +A short "how to use the API" is at the beginning of dns.go (this also will show
72 +when you call `godoc github.com/miekg/dns`).
73 +
74 +Example programs can be found in the `github.com/miekg/exdns` repository.
75 +
76 +## Supported RFCs
77 +
78 +*all of them*
79 +
80 +* 103{4,5} - DNS standard
81 +* 1348 - NSAP record
82 +* 1982 - Serial Arithmetic
83 +* 1876 - LOC record
84 +* 1995 - IXFR
85 +* 1996 - DNS notify
86 +* 2136 - DNS Update (dynamic updates)
87 +* 2181 - RRset definition - there is no RRset type though, just []RR
88 +* 2537 - RSAMD5 DNS keys
89 +* 2065 - DNSSEC (updated in later RFCs)
90 +* 2671 - EDNS record
91 +* 2782 - SRV record
92 +* 2845 - TSIG record
93 +* 2915 - NAPTR record
94 +* 2929 - DNS IANA Considerations
95 +* 3110 - RSASHA1 DNS keys
96 +* 3225 - DO bit (DNSSEC OK)
97 +* 340{1,2,3} - NAPTR record
98 +* 3445 - Limiting the scope of (DNS)KEY
99 +* 3597 - Unknown RRs
100 +* 4025 - IPSECKEY
101 +* 403{3,4,5} - DNSSEC + validation functions
102 +* 4255 - SSHFP record
103 +* 4343 - Case insensitivity
104 +* 4408 - SPF record
105 +* 4509 - SHA256 Hash in DS
106 +* 4592 - Wildcards in the DNS
107 +* 4635 - HMAC SHA TSIG
108 +* 4701 - DHCID
109 +* 4892 - id.server
110 +* 5001 - NSID
111 +* 5155 - NSEC3 record
112 +* 5205 - HIP record
113 +* 5702 - SHA2 in the DNS
114 +* 5936 - AXFR
115 +* 5966 - TCP implementation recommendations
116 +* 6605 - ECDSA
117 +* 6725 - IANA Registry Update
118 +* 6742 - ILNP DNS
119 +* 6891 - EDNS0 update
120 +* 6895 - DNS IANA considerations
121 +* 6975 - Algorithm Understanding in DNSSEC
122 +* 7043 - EUI48/EUI64 records
123 +* 7314 - DNS (EDNS) EXPIRE Option
124 +* xxxx - URI record (draft)
125 +* xxxx - EDNS0 DNS Update Lease (draft)
126 +
127 +## Loosely based upon
128 +
129 +* `ldns`
130 +* `NSD`
131 +* `Net::DNS`
132 +* `GRONG`
133 +
134 +## TODO
135 +
136 +* privatekey.Precompute() when signing?
137 +* Last remaining RRs: APL, ATMA, A6 and NXT and IPSECKEY;
138 +* Missing in parsing: ISDN, UNSPEC, ATMA;
139 +* CAA parsing is broken;
140 +* NSEC(3) cover/match/closest enclose;
141 +* Replies with TC bit are not parsed to the end;
Godeps/_workspace/src/github.com/miekg/dns/client.go new
+319
@@ -0,0 +1,319 @@
1 +package dns
2 +
3 +// A client implementation.
4 +
5 +import (
6 + "bytes"
7 + "io"
8 + "net"
9 + "time"
10 +)
11 +
12 +const dnsTimeout time.Duration = 2 * time.Second
13 +const tcpIdleTimeout time.Duration = 8 * time.Second
14 +
15 +// A Conn represents a connection to a DNS server.
16 +type Conn struct {
17 + net.Conn // a net.Conn holding the connection
18 + UDPSize uint16 // minimum receive buffer for UDP messages
19 + TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
20 + rtt time.Duration
21 + t time.Time
22 + tsigRequestMAC string
23 +}
24 +
25 +// A Client defines parameters for a DNS client.
26 +type Client struct {
27 + Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
28 + UDPSize uint16 // minimum receive buffer for UDP messages
29 + DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
30 + ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
31 + WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
32 + TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
33 + SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
34 + group singleflight
35 +}
36 +
37 +// Exchange performs a synchronous UDP query. It sends the message m to the address
38 +// contained in a and waits for an reply. Exchange does not retry a failed query, nor
39 +// will it fall back to TCP in case of truncation.
40 +// If you need to send a DNS message on an already existing connection, you can use the
41 +// following:
42 +//
43 +// co := &dns.Conn{Conn: c} // c is your net.Conn
44 +// co.WriteMsg(m)
45 +// in, err := co.ReadMsg()
46 +// co.Close()
47 +//
48 +func Exchange(m *Msg, a string) (r *Msg, err error) {
49 + var co *Conn
50 + co, err = DialTimeout("udp", a, dnsTimeout)
51 + if err != nil {
52 + return nil, err
53 + }
54 +
55 + defer co.Close()
56 + co.SetReadDeadline(time.Now().Add(dnsTimeout))
57 + co.SetWriteDeadline(time.Now().Add(dnsTimeout))
58 + if err = co.WriteMsg(m); err != nil {
59 + return nil, err
60 + }
61 + r, err = co.ReadMsg()
62 + return r, err
63 +}
64 +
65 +// ExchangeConn performs a synchronous query. It sends the message m via the connection
66 +// c and waits for a reply. The connection c is not closed by ExchangeConn.
67 +// This function is going away, but can easily be mimicked:
68 +//
69 +// co := &dns.Conn{Conn: c} // c is your net.Conn
70 +// co.WriteMsg(m)
71 +// in, _ := co.ReadMsg()
72 +// co.Close()
73 +//
74 +func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
75 + println("dns: this function is deprecated")
76 + co := new(Conn)
77 + co.Conn = c
78 + if err = co.WriteMsg(m); err != nil {
79 + return nil, err
80 + }
81 + r, err = co.ReadMsg()
82 + return r, err
83 +}
84 +
85 +// Exchange performs an synchronous query. It sends the message m to the address
86 +// contained in a and waits for an reply. Basic use pattern with a *dns.Client:
87 +//
88 +// c := new(dns.Client)
89 +// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
90 +//
91 +// Exchange does not retry a failed query, nor will it fall back to TCP in
92 +// case of truncation.
93 +func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
94 + if !c.SingleInflight {
95 + return c.exchange(m, a)
96 + }
97 + // This adds a bunch of garbage, TODO(miek).
98 + t := "nop"
99 + if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
100 + t = t1
101 + }
102 + cl := "nop"
103 + if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
104 + cl = cl1
105 + }
106 + r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
107 + return c.exchange(m, a)
108 + })
109 + if err != nil {
110 + return r, rtt, err
111 + }
112 + if shared {
113 + return r.Copy(), rtt, nil
114 + }
115 + return r, rtt, nil
116 +}
117 +
118 +func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
119 + timeout := dnsTimeout
120 + var co *Conn
121 + if c.DialTimeout != 0 {
122 + timeout = c.DialTimeout
123 + }
124 + if c.Net == "" {
125 + co, err = DialTimeout("udp", a, timeout)
126 + } else {
127 + co, err = DialTimeout(c.Net, a, timeout)
128 + }
129 + if err != nil {
130 + return nil, 0, err
131 + }
132 + timeout = dnsTimeout
133 + if c.ReadTimeout != 0 {
134 + timeout = c.ReadTimeout
135 + }
136 + co.SetReadDeadline(time.Now().Add(timeout))
137 + timeout = dnsTimeout
138 + if c.WriteTimeout != 0 {
139 + timeout = c.WriteTimeout
140 + }
141 + co.SetWriteDeadline(time.Now().Add(timeout))
142 + defer co.Close()
143 + opt := m.IsEdns0()
144 + // If EDNS0 is used use that for size.
145 + if opt != nil && opt.UDPSize() >= MinMsgSize {
146 + co.UDPSize = opt.UDPSize()
147 + }
148 + // Otherwise use the client's configured UDP size.
149 + if opt == nil && c.UDPSize >= MinMsgSize {
150 + co.UDPSize = c.UDPSize
151 + }
152 + co.TsigSecret = c.TsigSecret
153 + if err = co.WriteMsg(m); err != nil {
154 + return nil, 0, err
155 + }
156 + r, err = co.ReadMsg()
157 + return r, co.rtt, err
158 +}
159 +
160 +// ReadMsg reads a message from the connection co.
161 +// If the received message contains a TSIG record the transaction
162 +// signature is verified.
163 +func (co *Conn) ReadMsg() (*Msg, error) {
164 + var p []byte
165 + m := new(Msg)
166 + if _, ok := co.Conn.(*net.TCPConn); ok {
167 + p = make([]byte, MaxMsgSize)
168 + } else {
169 + if co.UDPSize >= 512 {
170 + p = make([]byte, co.UDPSize)
171 + } else {
172 + p = make([]byte, MinMsgSize)
173 + }
174 + }
175 + n, err := co.Read(p)
176 + if err != nil && n == 0 {
177 + return nil, err
178 + }
179 + p = p[:n]
180 + if err := m.Unpack(p); err != nil {
181 + return nil, err
182 + }
183 + co.rtt = time.Since(co.t)
184 + if t := m.IsTsig(); t != nil {
185 + if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
186 + return m, ErrSecret
187 + }
188 + // Need to work on the original message p, as that was used to calculate the tsig.
189 + err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
190 + }
191 + return m, err
192 +}
193 +
194 +// Read implements the net.Conn read method.
195 +func (co *Conn) Read(p []byte) (n int, err error) {
196 + if co.Conn == nil {
197 + return 0, ErrConnEmpty
198 + }
199 + if len(p) < 2 {
200 + return 0, io.ErrShortBuffer
201 + }
202 + if t, ok := co.Conn.(*net.TCPConn); ok {
203 + n, err = t.Read(p[0:2])
204 + if err != nil || n != 2 {
205 + return n, err
206 + }
207 + l, _ := unpackUint16(p[0:2], 0)
208 + if l == 0 {
209 + return 0, ErrShortRead
210 + }
211 + if int(l) > len(p) {
212 + return int(l), io.ErrShortBuffer
213 + }
214 + n, err = t.Read(p[:l])
215 + if err != nil {
216 + return n, err
217 + }
218 + i := n
219 + for i < int(l) {
220 + j, err := t.Read(p[i:int(l)])
221 + if err != nil {
222 + return i, err
223 + }
224 + i += j
225 + }
226 + n = i
227 + return n, err
228 + }
229 + // UDP connection
230 + n, err = co.Conn.Read(p)
231 + if err != nil {
232 + return n, err
233 + }
234 + return n, err
235 +}
236 +
237 +// WriteMsg sends a message throught the connection co.
238 +// If the message m contains a TSIG record the transaction
239 +// signature is calculated.
240 +func (co *Conn) WriteMsg(m *Msg) (err error) {
241 + var out []byte
242 + if t := m.IsTsig(); t != nil {
243 + mac := ""
244 + if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
245 + return ErrSecret
246 + }
247 + out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
248 + // Set for the next read, allthough only used in zone transfers
249 + co.tsigRequestMAC = mac
250 + } else {
251 + out, err = m.Pack()
252 + }
253 + if err != nil {
254 + return err
255 + }
256 + co.t = time.Now()
257 + if _, err = co.Write(out); err != nil {
258 + return err
259 + }
260 + return nil
261 +}
262 +
263 +// Write implements the net.Conn Write method.
264 +func (co *Conn) Write(p []byte) (n int, err error) {
265 + if t, ok := co.Conn.(*net.TCPConn); ok {
266 + lp := len(p)
267 + if lp < 2 {
268 + return 0, io.ErrShortBuffer
269 + }
270 + if lp > MaxMsgSize {
271 + return 0, &Error{err: "message too large"}
272 + }
273 + l := make([]byte, 2, lp+2)
274 + l[0], l[1] = packUint16(uint16(lp))
275 + p = append(l, p...)
276 + n, err := io.Copy(t, bytes.NewReader(p))
277 + return int(n), err
278 + }
279 + n, err = co.Conn.(*net.UDPConn).Write(p)
280 + return n, err
281 +}
282 +
283 +// Dial connects to the address on the named network.
284 +func Dial(network, address string) (conn *Conn, err error) {
285 + conn = new(Conn)
286 + conn.Conn, err = net.Dial(network, address)
287 + if err != nil {
288 + return nil, err
289 + }
290 + return conn, nil
291 +}
292 +
293 +// Dialtimeout acts like Dial but takes a timeout.
294 +func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
295 + conn = new(Conn)
296 + conn.Conn, err = net.DialTimeout(network, address, timeout)
297 + if err != nil {
298 + return nil, err
299 + }
300 + return conn, nil
301 +}
302 +
303 +// Close implements the net.Conn Close method.
304 +func (co *Conn) Close() error { return co.Conn.Close() }
305 +
306 +// LocalAddr implements the net.Conn LocalAddr method.
307 +func (co *Conn) LocalAddr() net.Addr { return co.Conn.LocalAddr() }
308 +
309 +// RemoteAddr implements the net.Conn RemoteAddr method.
310 +func (co *Conn) RemoteAddr() net.Addr { return co.Conn.RemoteAddr() }
311 +
312 +// SetDeadline implements the net.Conn SetDeadline method.
313 +func (co *Conn) SetDeadline(t time.Time) error { return co.Conn.SetDeadline(t) }
314 +
315 +// SetReadDeadline implements the net.Conn SetReadDeadline method.
316 +func (co *Conn) SetReadDeadline(t time.Time) error { return co.Conn.SetReadDeadline(t) }
317 +
318 +// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
319 +func (co *Conn) SetWriteDeadline(t time.Time) error { return co.Conn.SetWriteDeadline(t) }
Godeps/_workspace/src/github.com/miekg/dns/client_test.go new
+148
@@ -0,0 +1,148 @@
1 +package dns
2 +
3 +import (
4 + "testing"
5 + "time"
6 +)
7 +
8 +func TestClientSync(t *testing.T) {
9 + HandleFunc("miek.nl.", HelloServer)
10 + defer HandleRemove("miek.nl.")
11 +
12 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
13 + if err != nil {
14 + t.Fatalf("Unable to run test server: %s", err)
15 + }
16 + defer s.Shutdown()
17 +
18 + m := new(Msg)
19 + m.SetQuestion("miek.nl.", TypeSOA)
20 +
21 + c := new(Client)
22 + r, _, e := c.Exchange(m, addrstr)
23 + if e != nil {
24 + t.Logf("failed to exchange: %s", e.Error())
25 + t.Fail()
26 + }
27 + if r != nil && r.Rcode != RcodeSuccess {
28 + t.Log("failed to get an valid answer")
29 + t.Fail()
30 + t.Logf("%v\n", r)
31 + }
32 + // And now with plain Exchange().
33 + r, e = Exchange(m, addrstr)
34 + if e != nil {
35 + t.Logf("failed to exchange: %s", e.Error())
36 + t.Fail()
37 + }
38 + if r != nil && r.Rcode != RcodeSuccess {
39 + t.Log("failed to get an valid answer")
40 + t.Fail()
41 + t.Logf("%v\n", r)
42 + }
43 +}
44 +
45 +func TestClientEDNS0(t *testing.T) {
46 + HandleFunc("miek.nl.", HelloServer)
47 + defer HandleRemove("miek.nl.")
48 +
49 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
50 + if err != nil {
51 + t.Fatalf("Unable to run test server: %s", err)
52 + }
53 + defer s.Shutdown()
54 +
55 + m := new(Msg)
56 + m.SetQuestion("miek.nl.", TypeDNSKEY)
57 +
58 + m.SetEdns0(2048, true)
59 +
60 + c := new(Client)
61 + r, _, e := c.Exchange(m, addrstr)
62 + if e != nil {
63 + t.Logf("failed to exchange: %s", e.Error())
64 + t.Fail()
65 + }
66 +
67 + if r != nil && r.Rcode != RcodeSuccess {
68 + t.Log("failed to get an valid answer")
69 + t.Fail()
70 + t.Logf("%v\n", r)
71 + }
72 +}
73 +
74 +func TestSingleSingleInflight(t *testing.T) {
75 + HandleFunc("miek.nl.", HelloServer)
76 + defer HandleRemove("miek.nl.")
77 +
78 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
79 + if err != nil {
80 + t.Fatalf("Unable to run test server: %s", err)
81 + }
82 + defer s.Shutdown()
83 +
84 + m := new(Msg)
85 + m.SetQuestion("miek.nl.", TypeDNSKEY)
86 +
87 + c := new(Client)
88 + c.SingleInflight = true
89 + nr := 10
90 + ch := make(chan time.Duration)
91 + for i := 0; i < nr; i++ {
92 + go func() {
93 + _, rtt, _ := c.Exchange(m, addrstr)
94 + ch <- rtt
95 + }()
96 + }
97 + i := 0
98 + var first time.Duration
99 + // With inflight *all* rtt are identical, and by doing actual lookups
100 + // the changes that this is a coincidence is small.
101 +Loop:
102 + for {
103 + select {
104 + case rtt := <-ch:
105 + if i == 0 {
106 + first = rtt
107 + } else {
108 + if first != rtt {
109 + t.Log("all rtts should be equal")
110 + t.Fail()
111 + }
112 + }
113 + i++
114 + if i == 10 {
115 + break Loop
116 + }
117 + }
118 + }
119 +}
120 +
121 +// ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG.
122 +func ExampleUpdateLeaseTSIG(t *testing.T) {
123 + m := new(Msg)
124 + m.SetUpdate("t.local.ip6.io.")
125 + rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
126 + rrs := make([]RR, 1)
127 + rrs[0] = rr
128 + m.Insert(rrs)
129 +
130 + lease_rr := new(OPT)
131 + lease_rr.Hdr.Name = "."
132 + lease_rr.Hdr.Rrtype = TypeOPT
133 + e := new(EDNS0_UL)
134 + e.Code = EDNS0UL
135 + e.Lease = 120
136 + lease_rr.Option = append(lease_rr.Option, e)
137 + m.Extra = append(m.Extra, lease_rr)
138 +
139 + c := new(Client)
140 + m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
141 + c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}
142 +
143 + _, _, err := c.Exchange(m, "127.0.0.1:53")
144 + if err != nil {
145 + t.Log(err.Error())
146 + t.Fail()
147 + }
148 +}
Godeps/_workspace/src/github.com/miekg/dns/clientconfig.go new
+94
@@ -0,0 +1,94 @@
1 +package dns
2 +
3 +import (
4 + "bufio"
5 + "os"
6 + "strconv"
7 + "strings"
8 +)
9 +
10 +// Wraps the contents of the /etc/resolv.conf.
11 +type ClientConfig struct {
12 + Servers []string // servers to use
13 + Search []string // suffixes to append to local name
14 + Port string // what port to use
15 + Ndots int // number of dots in name to trigger absolute lookup
16 + Timeout int // seconds before giving up on packet
17 + Attempts int // lost packets before giving up on server, not used in the package dns
18 +}
19 +
20 +// ClientConfigFromFile parses a resolv.conf(5) like file and returns
21 +// a *ClientConfig.
22 +func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
23 + file, err := os.Open(resolvconf)
24 + if err != nil {
25 + return nil, err
26 + }
27 + defer file.Close()
28 + c := new(ClientConfig)
29 + b := bufio.NewReader(file)
30 + c.Servers = make([]string, 0)
31 + c.Search = make([]string, 0)
32 + c.Port = "53"
33 + c.Ndots = 1
34 + c.Timeout = 5
35 + c.Attempts = 2
36 + for line, ok := b.ReadString('\n'); ok == nil; line, ok = b.ReadString('\n') {
37 + f := strings.Fields(line)
38 + if len(f) < 1 {
39 + continue
40 + }
41 + switch f[0] {
42 + case "nameserver": // add one name server
43 + if len(f) > 1 {
44 + // One more check: make sure server name is
45 + // just an IP address. Otherwise we need DNS
46 + // to look it up.
47 + name := f[1]
48 + c.Servers = append(c.Servers, name)
49 + }
50 +
51 + case "domain": // set search path to just this domain
52 + if len(f) > 1 {
53 + c.Search = make([]string, 1)
54 + c.Search[0] = f[1]
55 + } else {
56 + c.Search = make([]string, 0)
57 + }
58 +
59 + case "search": // set search path to given servers
60 + c.Search = make([]string, len(f)-1)
61 + for i := 0; i < len(c.Search); i++ {
62 + c.Search[i] = f[i+1]
63 + }
64 +
65 + case "options": // magic options
66 + for i := 1; i < len(f); i++ {
67 + s := f[i]
68 + switch {
69 + case len(s) >= 6 && s[:6] == "ndots:":
70 + n, _ := strconv.Atoi(s[6:])
71 + if n < 1 {
72 + n = 1
73 + }
74 + c.Ndots = n
75 + case len(s) >= 8 && s[:8] == "timeout:":
76 + n, _ := strconv.Atoi(s[8:])
77 + if n < 1 {
78 + n = 1
79 + }
80 + c.Timeout = n
81 + case len(s) >= 8 && s[:9] == "attempts:":
82 + n, _ := strconv.Atoi(s[9:])
83 + if n < 1 {
84 + n = 1
85 + }
86 + c.Attempts = n
87 + case s == "rotate":
88 + /* not imp */
89 + }
90 + }
91 + }
92 + }
93 + return c, nil
94 +}
Godeps/_workspace/src/github.com/miekg/dns/defaults.go new
+244
@@ -0,0 +1,244 @@
1 +package dns
2 +
3 +import (
4 + "errors"
5 + "net"
6 + "strconv"
7 +)
8 +
9 +const hexDigit = "0123456789abcdef"
10 +
11 +// Everything is assumed in ClassINET.
12 +
13 +// SetReply creates a reply message from a request message.
14 +func (dns *Msg) SetReply(request *Msg) *Msg {
15 + dns.Id = request.Id
16 + dns.RecursionDesired = request.RecursionDesired // Copy rd bit
17 + dns.Response = true
18 + dns.Opcode = OpcodeQuery
19 + dns.Rcode = RcodeSuccess
20 + if len(request.Question) > 0 {
21 + dns.Question = make([]Question, 1)
22 + dns.Question[0] = request.Question[0]
23 + }
24 + return dns
25 +}
26 +
27 +// SetQuestion creates a question message.
28 +func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
29 + dns.Id = Id()
30 + dns.RecursionDesired = true
31 + dns.Question = make([]Question, 1)
32 + dns.Question[0] = Question{z, t, ClassINET}
33 + return dns
34 +}
35 +
36 +// SetNotify creates a notify message.
37 +func (dns *Msg) SetNotify(z string) *Msg {
38 + dns.Opcode = OpcodeNotify
39 + dns.Authoritative = true
40 + dns.Id = Id()
41 + dns.Question = make([]Question, 1)
42 + dns.Question[0] = Question{z, TypeSOA, ClassINET}
43 + return dns
44 +}
45 +
46 +// SetRcode creates an error message suitable for the request.
47 +func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
48 + dns.SetReply(request)
49 + dns.Rcode = rcode
50 + return dns
51 +}
52 +
53 +// SetRcodeFormatError creates a message with FormError set.
54 +func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
55 + dns.Rcode = RcodeFormatError
56 + dns.Opcode = OpcodeQuery
57 + dns.Response = true
58 + dns.Authoritative = false
59 + dns.Id = request.Id
60 + return dns
61 +}
62 +
63 +// SetUpdate makes the message a dynamic update message. It
64 +// sets the ZONE section to: z, TypeSOA, ClassINET.
65 +func (dns *Msg) SetUpdate(z string) *Msg {
66 + dns.Id = Id()
67 + dns.Response = false
68 + dns.Opcode = OpcodeUpdate
69 + dns.Compress = false // BIND9 cannot handle compression
70 + dns.Question = make([]Question, 1)
71 + dns.Question[0] = Question{z, TypeSOA, ClassINET}
72 + return dns
73 +}
74 +
75 +// SetIxfr creates message for requesting an IXFR.
76 +func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
77 + dns.Id = Id()
78 + dns.Question = make([]Question, 1)
79 + dns.Ns = make([]RR, 1)
80 + s := new(SOA)
81 + s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
82 + s.Serial = serial
83 + s.Ns = ns
84 + s.Mbox = mbox
85 + dns.Question[0] = Question{z, TypeIXFR, ClassINET}
86 + dns.Ns[0] = s
87 + return dns
88 +}
89 +
90 +// SetAxfr creates message for requesting an AXFR.
91 +func (dns *Msg) SetAxfr(z string) *Msg {
92 + dns.Id = Id()
93 + dns.Question = make([]Question, 1)
94 + dns.Question[0] = Question{z, TypeAXFR, ClassINET}
95 + return dns
96 +}
97 +
98 +// SetTsig appends a TSIG RR to the message.
99 +// This is only a skeleton TSIG RR that is added as the last RR in the
100 +// additional section. The Tsig is calculated when the message is being send.
101 +func (dns *Msg) SetTsig(z, algo string, fudge, timesigned int64) *Msg {
102 + t := new(TSIG)
103 + t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
104 + t.Algorithm = algo
105 + t.Fudge = 300
106 + t.TimeSigned = uint64(timesigned)
107 + t.OrigId = dns.Id
108 + dns.Extra = append(dns.Extra, t)
109 + return dns
110 +}
111 +
112 +// SetEdns0 appends a EDNS0 OPT RR to the message.
113 +// TSIG should always the last RR in a message.
114 +func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
115 + e := new(OPT)
116 + e.Hdr.Name = "."
117 + e.Hdr.Rrtype = TypeOPT
118 + e.SetUDPSize(udpsize)
119 + if do {
120 + e.SetDo()
121 + }
122 + dns.Extra = append(dns.Extra, e)
123 + return dns
124 +}
125 +
126 +// IsTsig checks if the message has a TSIG record as the last record
127 +// in the additional section. It returns the TSIG record found or nil.
128 +func (dns *Msg) IsTsig() *TSIG {
129 + if len(dns.Extra) > 0 {
130 + if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
131 + return dns.Extra[len(dns.Extra)-1].(*TSIG)
132 + }
133 + }
134 + return nil
135 +}
136 +
137 +// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0
138 +// record in the additional section will do. It returns the OPT record
139 +// found or nil.
140 +func (dns *Msg) IsEdns0() *OPT {
141 + for _, r := range dns.Extra {
142 + if r.Header().Rrtype == TypeOPT {
143 + return r.(*OPT)
144 + }
145 + }
146 + return nil
147 +}
148 +
149 +// IsDomainName checks if s is a valid domainname, it returns
150 +// the number of labels and true, when a domain name is valid.
151 +// Note that non fully qualified domain name is considered valid, in this case the
152 +// last label is counted in the number of labels.
153 +// When false is returned the number of labels is not defined.
154 +func IsDomainName(s string) (labels int, ok bool) {
155 + _, labels, err := packDomainName(s, nil, 0, nil, false)
156 + return labels, err == nil
157 +}
158 +
159 +// IsSubDomain checks if child is indeed a child of the parent. Both child and
160 +// parent are *not* downcased before doing the comparison.
161 +func IsSubDomain(parent, child string) bool {
162 + // Entire child is contained in parent
163 + return CompareDomainName(parent, child) == CountLabel(parent)
164 +}
165 +
166 +// IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet.
167 +// The checking is performed on the binary payload.
168 +func IsMsg(buf []byte) error {
169 + // Header
170 + if len(buf) < 12 {
171 + return errors.New("dns: bad message header")
172 + }
173 + // Header: Opcode
174 + // TODO(miek): more checks here, e.g. check all header bits.
175 + return nil
176 +}
177 +
178 +// IsFqdn checks if a domain name is fully qualified.
179 +func IsFqdn(s string) bool {
180 + l := len(s)
181 + if l == 0 {
182 + return false
183 + }
184 + return s[l-1] == '.'
185 +}
186 +
187 +// Fqdns return the fully qualified domain name from s.
188 +// If s is already fully qualified, it behaves as the identity function.
189 +func Fqdn(s string) string {
190 + if IsFqdn(s) {
191 + return s
192 + }
193 + return s + "."
194 +}
195 +
196 +// Copied from the official Go code.
197 +
198 +// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
199 +// address suitable for reverse DNS (PTR) record lookups or an error if it fails
200 +// to parse the IP address.
201 +func ReverseAddr(addr string) (arpa string, err error) {
202 + ip := net.ParseIP(addr)
203 + if ip == nil {
204 + return "", &Error{err: "unrecognized address: " + addr}
205 + }
206 + if ip.To4() != nil {
207 + return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." +
208 + strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil
209 + }
210 + // Must be IPv6
211 + buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
212 + // Add it, in reverse, to the buffer
213 + for i := len(ip) - 1; i >= 0; i-- {
214 + v := ip[i]
215 + buf = append(buf, hexDigit[v&0xF])
216 + buf = append(buf, '.')
217 + buf = append(buf, hexDigit[v>>4])
218 + buf = append(buf, '.')
219 + }
220 + // Append "ip6.arpa." and return (buf already has the final .)
221 + buf = append(buf, "ip6.arpa."...)
222 + return string(buf), nil
223 +}
224 +
225 +// String returns the string representation for the type t.
226 +func (t Type) String() string {
227 + if t1, ok := TypeToString[uint16(t)]; ok {
228 + return t1
229 + }
230 + return "TYPE" + strconv.Itoa(int(t))
231 +}
232 +
233 +// String returns the string representation for the class c.
234 +func (c Class) String() string {
235 + if c1, ok := ClassToString[uint16(c)]; ok {
236 + return c1
237 + }
238 + return "CLASS" + strconv.Itoa(int(c))
239 +}
240 +
241 +// String returns the string representation for the name n.
242 +func (n Name) String() string {
243 + return sprintName(string(n))
244 +}
Godeps/_workspace/src/github.com/miekg/dns/dns.go new
+191
@@ -0,0 +1,191 @@
1 +// Package dns implements a full featured interface to the Domain Name System.
2 +// Server- and client-side programming is supported.
3 +// The package allows complete control over what is send out to the DNS. The package
4 +// API follows the less-is-more principle, by presenting a small, clean interface.
5 +//
6 +// The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
7 +// TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
8 +// Note that domain names MUST be fully qualified, before sending them, unqualified
9 +// names in a message will result in a packing failure.
10 +//
11 +// Resource records are native types. They are not stored in wire format.
12 +// Basic usage pattern for creating a new resource record:
13 +//
14 +// r := new(dns.MX)
15 +// r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
16 +// r.Preference = 10
17 +// r.Mx = "mx.miek.nl."
18 +//
19 +// Or directly from a string:
20 +//
21 +// mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
22 +//
23 +// Or when the default TTL (3600) and class (IN) suit you:
24 +//
25 +// mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
26 +//
27 +// Or even:
28 +//
29 +// mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
30 +//
31 +// In the DNS messages are exchanged, these messages contain resource
32 +// records (sets). Use pattern for creating a message:
33 +//
34 +// m := new(dns.Msg)
35 +// m.SetQuestion("miek.nl.", dns.TypeMX)
36 +//
37 +// Or when not certain if the domain name is fully qualified:
38 +//
39 +// m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
40 +//
41 +// The message m is now a message with the question section set to ask
42 +// the MX records for the miek.nl. zone.
43 +//
44 +// The following is slightly more verbose, but more flexible:
45 +//
46 +// m1 := new(dns.Msg)
47 +// m1.Id = dns.Id()
48 +// m1.RecursionDesired = true
49 +// m1.Question = make([]dns.Question, 1)
50 +// m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
51 +//
52 +// After creating a message it can be send.
53 +// Basic use pattern for synchronous querying the DNS at a
54 +// server configured on 127.0.0.1 and port 53:
55 +//
56 +// c := new(dns.Client)
57 +// in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
58 +//
59 +// Suppressing
60 +// multiple outstanding queries (with the same question, type and class) is as easy as setting:
61 +//
62 +// c.SingleInflight = true
63 +//
64 +// If these "advanced" features are not needed, a simple UDP query can be send,
65 +// with:
66 +//
67 +// in, err := dns.Exchange(m1, "127.0.0.1:53")
68 +//
69 +// When this functions returns you will get dns message. A dns message consists
70 +// out of four sections.
71 +// The question section: in.Question, the answer section: in.Answer,
72 +// the authority section: in.Ns and the additional section: in.Extra.
73 +//
74 +// Each of these sections (except the Question section) contain a []RR. Basic
75 +// use pattern for accessing the rdata of a TXT RR as the first RR in
76 +// the Answer section:
77 +//
78 +// if t, ok := in.Answer[0].(*dns.TXT); ok {
79 +// // do something with t.Txt
80 +// }
81 +//
82 +// Domain Name and TXT Character String Representations
83 +//
84 +// Both domain names and TXT character strings are converted to presentation
85 +// form both when unpacked and when converted to strings.
86 +//
87 +// For TXT character strings, tabs, carriage returns and line feeds will be
88 +// converted to \t, \r and \n respectively. Back slashes and quotations marks
89 +// will be escaped. Bytes below 32 and above 127 will be converted to \DDD
90 +// form.
91 +//
92 +// For domain names, in addition to the above rules brackets, periods,
93 +// spaces, semicolons and the at symbol are escaped.
94 +package dns
95 +
96 +import "strconv"
97 +
98 +const (
99 + year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
100 + DefaultMsgSize = 4096 // Standard default for larger than 512 bytes.
101 + MinMsgSize = 512 // Minimal size of a DNS packet.
102 + MaxMsgSize = 65536 // Largest possible DNS packet.
103 + defaultTtl = 3600 // Default TTL.
104 +)
105 +
106 +// Error represents a DNS error
107 +type Error struct{ err string }
108 +
109 +func (e *Error) Error() string {
110 + if e == nil {
111 + return "dns: <nil>"
112 + }
113 + return "dns: " + e.err
114 +}
115 +
116 +// An RR represents a resource record.
117 +type RR interface {
118 + // Header returns the header of an resource record. The header contains
119 + // everything up to the rdata.
120 + Header() *RR_Header
121 + // String returns the text representation of the resource record.
122 + String() string
123 + // copy returns a copy of the RR
124 + copy() RR
125 + // len returns the length (in octets) of the uncompressed RR in wire format.
126 + len() int
127 +}
128 +
129 +// DNS resource records.
130 +// There are many types of RRs,
131 +// but they all share the same header.
132 +type RR_Header struct {
133 + Name string `dns:"cdomain-name"`
134 + Rrtype uint16
135 + Class uint16
136 + Ttl uint32
137 + Rdlength uint16 // length of data after header
138 +}
139 +
140 +func (h *RR_Header) Header() *RR_Header { return h }
141 +
142 +// Just to imlement the RR interface
143 +func (h *RR_Header) copy() RR { return nil }
144 +
145 +func (h *RR_Header) copyHeader() *RR_Header {
146 + r := new(RR_Header)
147 + r.Name = h.Name
148 + r.Rrtype = h.Rrtype
149 + r.Class = h.Class
150 + r.Ttl = h.Ttl
151 + r.Rdlength = h.Rdlength
152 + return r
153 +}
154 +
155 +func (h *RR_Header) String() string {
156 + var s string
157 +
158 + if h.Rrtype == TypeOPT {
159 + s = ";"
160 + // and maybe other things
161 + }
162 +
163 + s += sprintName(h.Name) + "\t"
164 + s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
165 + s += Class(h.Class).String() + "\t"
166 + s += Type(h.Rrtype).String() + "\t"
167 + return s
168 +}
169 +
170 +func (h *RR_Header) len() int {
171 + l := len(h.Name) + 1
172 + l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
173 + return l
174 +}
175 +
176 +// ToRFC3597 converts a known RR to the unknown RR representation
177 +// from RFC 3597.
178 +func (rr *RFC3597) ToRFC3597(r RR) error {
179 + buf := make([]byte, r.len()*2)
180 + off, err := PackStruct(r, buf, 0)
181 + if err != nil {
182 + return err
183 + }
184 + buf = buf[:off]
185 + rawSetRdlength(buf, 0, off)
186 + _, err = UnpackStruct(rr, buf, 0)
187 + if err != nil {
188 + return err
189 + }
190 + return nil
191 +}
Godeps/_workspace/src/github.com/miekg/dns/dns_test.go new
+538
@@ -0,0 +1,538 @@
1 +package dns
2 +
3 +import (
4 + "encoding/hex"
5 + "net"
6 + "testing"
7 +)
8 +
9 +func TestPackUnpack(t *testing.T) {
10 + out := new(Msg)
11 + out.Answer = make([]RR, 1)
12 + key := new(DNSKEY)
13 + key = &DNSKEY{Flags: 257, Protocol: 3, Algorithm: RSASHA1}
14 + key.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 3600}
15 + key.PublicKey = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
16 +
17 + out.Answer[0] = key
18 + msg, err := out.Pack()
19 + if err != nil {
20 + t.Log("failed to pack msg with DNSKEY")
21 + t.Fail()
22 + }
23 + in := new(Msg)
24 + if in.Unpack(msg) != nil {
25 + t.Log("failed to unpack msg with DNSKEY")
26 + t.Fail()
27 + }
28 +
29 + sig := new(RRSIG)
30 + sig = &RRSIG{TypeCovered: TypeDNSKEY, Algorithm: RSASHA1, Labels: 2,
31 + OrigTtl: 3600, Expiration: 4000, Inception: 4000, KeyTag: 34641, SignerName: "miek.nl.",
32 + Signature: "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"}
33 + sig.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeRRSIG, Class: ClassINET, Ttl: 3600}
34 +
35 + out.Answer[0] = sig
36 + msg, err = out.Pack()
37 + if err != nil {
38 + t.Log("failed to pack msg with RRSIG")
39 + t.Fail()
40 + }
41 +
42 + if in.Unpack(msg) != nil {
43 + t.Log("failed to unpack msg with RRSIG")
44 + t.Fail()
45 + }
46 +}
47 +
48 +func TestPackUnpack2(t *testing.T) {
49 + m := new(Msg)
50 + m.Extra = make([]RR, 1)
51 + m.Answer = make([]RR, 1)
52 + dom := "miek.nl."
53 + rr := new(A)
54 + rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0}
55 + rr.A = net.IPv4(127, 0, 0, 1)
56 +
57 + x := new(TXT)
58 + x.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
59 + x.Txt = []string{"heelalaollo"}
60 +
61 + m.Extra[0] = x
62 + m.Answer[0] = rr
63 + _, err := m.Pack()
64 + if err != nil {
65 + t.Log("Packing failed: " + err.Error())
66 + t.Fail()
67 + return
68 + }
69 +}
70 +
71 +func TestPackUnpack3(t *testing.T) {
72 + m := new(Msg)
73 + m.Extra = make([]RR, 2)
74 + m.Answer = make([]RR, 1)
75 + dom := "miek.nl."
76 + rr := new(A)
77 + rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0}
78 + rr.A = net.IPv4(127, 0, 0, 1)
79 +
80 + x1 := new(TXT)
81 + x1.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
82 + x1.Txt = []string{}
83 +
84 + x2 := new(TXT)
85 + x2.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
86 + x2.Txt = []string{"heelalaollo"}
87 +
88 + m.Extra[0] = x1
89 + m.Extra[1] = x2
90 + m.Answer[0] = rr
91 + b, err := m.Pack()
92 + if err != nil {
93 + t.Log("packing failed: " + err.Error())
94 + t.Fail()
95 + return
96 + }
97 +
98 + var unpackMsg Msg
99 + err = unpackMsg.Unpack(b)
100 + if err != nil {
101 + t.Log("unpacking failed")
102 + t.Fail()
103 + return
104 + }
105 +}
106 +
107 +func TestBailiwick(t *testing.T) {
108 + yes := map[string]string{
109 + "miek.nl": "ns.miek.nl",
110 + ".": "miek.nl",
111 + }
112 + for parent, child := range yes {
113 + if !IsSubDomain(parent, child) {
114 + t.Logf("%s should be child of %s\n", child, parent)
115 + t.Logf("comparelabels %d", CompareDomainName(parent, child))
116 + t.Logf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
117 + t.Fail()
118 + }
119 + }
120 + no := map[string]string{
121 + "www.miek.nl": "ns.miek.nl",
122 + "m\\.iek.nl": "ns.miek.nl",
123 + "w\\.iek.nl": "w.iek.nl",
124 + "p\\\\.iek.nl": "ns.p.iek.nl", // p\\.iek.nl , literal \ in domain name
125 + "miek.nl": ".",
126 + }
127 + for parent, child := range no {
128 + if IsSubDomain(parent, child) {
129 + t.Logf("%s should not be child of %s\n", child, parent)
130 + t.Logf("comparelabels %d", CompareDomainName(parent, child))
131 + t.Logf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
132 + t.Fail()
133 + }
134 + }
135 +}
136 +
137 +func TestPack(t *testing.T) {
138 + rr := []string{"US. 86400 IN NSEC 0-.us. NS SOA RRSIG NSEC DNSKEY TYPE65534"}
139 + m := new(Msg)
140 + var err error
141 + m.Answer = make([]RR, 1)
142 + for _, r := range rr {
143 + m.Answer[0], err = NewRR(r)
144 + if err != nil {
145 + t.Logf("failed to create RR: %s\n", err.Error())
146 + t.Fail()
147 + continue
148 + }
149 + if _, err := m.Pack(); err != nil {
150 + t.Logf("packing failed: %s\n", err.Error())
151 + t.Fail()
152 + }
153 + }
154 + x := new(Msg)
155 + ns, _ := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org")
156 + ns.(*NS).Ns = "a.ntpns.org"
157 + x.Ns = append(m.Ns, ns)
158 + x.Ns = append(m.Ns, ns)
159 + x.Ns = append(m.Ns, ns)
160 + // This crashes due to the fact the a.ntpns.org isn't a FQDN
161 + // How to recover() from a remove panic()?
162 + if _, err := x.Pack(); err == nil {
163 + t.Log("packing should fail")
164 + t.Fail()
165 + }
166 + x.Answer = make([]RR, 1)
167 + x.Answer[0], err = NewRR(rr[0])
168 + if _, err := x.Pack(); err == nil {
169 + t.Log("packing should fail")
170 + t.Fail()
171 + }
172 + x.Question = make([]Question, 1)
173 + x.Question[0] = Question{";sd#edddds鍛↙赏‘℅∥↙xzztsestxssweewwsssstx@s@Z嵌e@cn.pool.ntp.org.", TypeA, ClassINET}
174 + if _, err := x.Pack(); err == nil {
175 + t.Log("packing should fail")
176 + t.Fail()
177 + }
178 +}
179 +
180 +func TestPackNAPTR(t *testing.T) {
181 + for _, n := range []string{
182 + `apple.com. IN NAPTR 100 50 "se" "SIP+D2U" "" _sip._udp.apple.com.`,
183 + `apple.com. IN NAPTR 90 50 "se" "SIP+D2T" "" _sip._tcp.apple.com.`,
184 + `apple.com. IN NAPTR 50 50 "se" "SIPS+D2T" "" _sips._tcp.apple.com.`,
185 + } {
186 + rr, _ := NewRR(n)
187 + msg := make([]byte, rr.len())
188 + if off, err := PackRR(rr, msg, 0, nil, false); err != nil {
189 + t.Logf("packing failed: %s", err.Error())
190 + t.Logf("length %d, need more than %d\n", rr.len(), off)
191 + t.Fail()
192 + } else {
193 + t.Logf("buf size needed: %d\n", off)
194 + }
195 + }
196 +}
197 +
198 +func TestCompressLength(t *testing.T) {
199 + m := new(Msg)
200 + m.SetQuestion("miek.nl", TypeMX)
201 + ul := m.Len()
202 + m.Compress = true
203 + if ul != m.Len() {
204 + t.Fatalf("should be equal")
205 + }
206 +}
207 +
208 +// Does the predicted length match final packed length?
209 +func TestMsgCompressLength(t *testing.T) {
210 + makeMsg := func(question string, ans, ns, e []RR) *Msg {
211 + msg := new(Msg)
212 + msg.SetQuestion(Fqdn(question), TypeANY)
213 + msg.Answer = append(msg.Answer, ans...)
214 + msg.Ns = append(msg.Ns, ns...)
215 + msg.Extra = append(msg.Extra, e...)
216 + msg.Compress = true
217 + return msg
218 + }
219 +
220 + name1 := "12345678901234567890123456789012345.12345678.123."
221 + rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
222 + rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
223 + tests := []*Msg{
224 + makeMsg(name1, []RR{rrA}, nil, nil),
225 + makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
226 +
227 + for _, msg := range tests {
228 + predicted := msg.Len()
229 + buf, err := msg.Pack()
230 + if err != nil {
231 + t.Error(err)
232 + t.Fail()
233 + }
234 + if predicted < len(buf) {
235 + t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d\n",
236 + msg.Question[0].Name, len(msg.Answer), predicted, len(buf))
237 + t.Fail()
238 + }
239 + }
240 +}
241 +
242 +func TestMsgLength(t *testing.T) {
243 + makeMsg := func(question string, ans, ns, e []RR) *Msg {
244 + msg := new(Msg)
245 + msg.SetQuestion(Fqdn(question), TypeANY)
246 + msg.Answer = append(msg.Answer, ans...)
247 + msg.Ns = append(msg.Ns, ns...)
248 + msg.Extra = append(msg.Extra, e...)
249 + return msg
250 + }
251 +
252 + name1 := "12345678901234567890123456789012345.12345678.123."
253 + rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
254 + rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
255 + tests := []*Msg{
256 + makeMsg(name1, []RR{rrA}, nil, nil),
257 + makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
258 +
259 + for _, msg := range tests {
260 + predicted := msg.Len()
261 + buf, err := msg.Pack()
262 + if err != nil {
263 + t.Error(err)
264 + t.Fail()
265 + }
266 + if predicted < len(buf) {
267 + t.Errorf("predicted length is wrong: predicted %s (len=%d), actual %d\n",
268 + msg.Question[0].Name, predicted, len(buf))
269 + t.Fail()
270 + }
271 + }
272 +}
273 +
274 +func TestMsgLength2(t *testing.T) {
275 + // Serialized replies
276 + var testMessages = []string{
277 + // google.com. IN A?
278 + "064e81800001000b0004000506676f6f676c6503636f6d0000010001c00c00010001000000050004adc22986c00c00010001000000050004adc22987c00c00010001000000050004adc22988c00c00010001000000050004adc22989c00c00010001000000050004adc2298ec00c00010001000000050004adc22980c00c00010001000000050004adc22981c00c00010001000000050004adc22982c00c00010001000000050004adc22983c00c00010001000000050004adc22984c00c00010001000000050004adc22985c00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc0d800010001000000050004d8ef200ac0ea00010001000000050004d8ef220ac0fc00010001000000050004d8ef240ac10e00010001000000050004d8ef260a0000290500000000050000",
279 + // amazon.com. IN A? (reply has no EDNS0 record)
280 + // TODO(miek): this one is off-by-one, need to find out why
281 + //"6de1818000010004000a000806616d617a6f6e03636f6d0000010001c00c000100010000000500044815c2d4c00c000100010000000500044815d7e8c00c00010001000000050004b02062a6c00c00010001000000050004cdfbf236c00c000200010000000500140570646e733408756c747261646e73036f726700c00c000200010000000500150570646e733508756c747261646e7304696e666f00c00c000200010000000500160570646e733608756c747261646e7302636f02756b00c00c00020001000000050014036e7331037033310664796e656374036e657400c00c00020001000000050006036e7332c0cfc00c00020001000000050006036e7333c0cfc00c00020001000000050006036e7334c0cfc00c000200010000000500110570646e733108756c747261646e73c0dac00c000200010000000500080570646e7332c127c00c000200010000000500080570646e7333c06ec0cb00010001000000050004d04e461fc0eb00010001000000050004cc0dfa1fc0fd00010001000000050004d04e471fc10f00010001000000050004cc0dfb1fc12100010001000000050004cc4a6c01c121001c000100000005001020010502f3ff00000000000000000001c13e00010001000000050004cc4a6d01c13e001c0001000000050010261000a1101400000000000000000001",
282 + // yahoo.com. IN A?
283 + "fc2d81800001000300070008057961686f6f03636f6d0000010001c00c00010001000000050004628afd6dc00c00010001000000050004628bb718c00c00010001000000050004cebe242dc00c00020001000000050006036e7336c00cc00c00020001000000050006036e7338c00cc00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7335c00cc07b0001000100000005000444b48310c08d00010001000000050004448eff10c09f00010001000000050004cb54dd35c0b100010001000000050004628a0b9dc0c30001000100000005000477a0f77cc05700010001000000050004ca2bdfaac06900010001000000050004caa568160000290500000000050000",
284 + // microsoft.com. IN A?
285 + "f4368180000100020005000b096d6963726f736f667403636f6d0000010001c00c0001000100000005000440040b25c00c0001000100000005000441373ac9c00c0002000100000005000e036e7331046d736674036e657400c00c00020001000000050006036e7332c04fc00c00020001000000050006036e7333c04fc00c00020001000000050006036e7334c04fc00c00020001000000050006036e7335c04fc04b000100010000000500044137253ec04b001c00010000000500102a010111200500000000000000010001c0650001000100000005000440043badc065001c00010000000500102a010111200600060000000000010001c07700010001000000050004d5c7b435c077001c00010000000500102a010111202000000000000000010001c08900010001000000050004cf2e4bfec089001c00010000000500102404f800200300000000000000010001c09b000100010000000500044137e28cc09b001c00010000000500102a010111200f000100000000000100010000290500000000050000",
286 + // google.com. IN MX?
287 + "724b8180000100050004000b06676f6f676c6503636f6d00000f0001c00c000f000100000005000c000a056173706d78016cc00cc00c000f0001000000050009001404616c7431c02ac00c000f0001000000050009001e04616c7432c02ac00c000f0001000000050009002804616c7433c02ac00c000f0001000000050009003204616c7434c02ac00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7331c00cc02a00010001000000050004adc2421bc02a001c00010000000500102a00145040080c01000000000000001bc04200010001000000050004adc2461bc05700010001000000050004adc2451bc06c000100010000000500044a7d8f1bc081000100010000000500044a7d191bc0ca00010001000000050004d8ef200ac09400010001000000050004d8ef220ac0a600010001000000050004d8ef240ac0b800010001000000050004d8ef260a0000290500000000050000",
288 + // reddit.com. IN A?
289 + "12b98180000100080000000c0672656464697403636f6d0000020001c00c0002000100000005000f046175733204616b616d036e657400c00c000200010000000500070475736534c02dc00c000200010000000500070475737733c02dc00c000200010000000500070475737735c02dc00c00020001000000050008056173696131c02dc00c00020001000000050008056173696139c02dc00c00020001000000050008056e73312d31c02dc00c0002000100000005000a076e73312d313935c02dc02800010001000000050004c30a242ec04300010001000000050004451f1d39c05600010001000000050004451f3bc7c0690001000100000005000460073240c07c000100010000000500046007fb81c090000100010000000500047c283484c090001c00010000000500102a0226f0006700000000000000000064c0a400010001000000050004c16c5b01c0a4001c000100000005001026001401000200000000000000000001c0b800010001000000050004c16c5bc3c0b8001c0001000000050010260014010002000000000000000000c30000290500000000050000",
290 + }
291 +
292 + for i, hexData := range testMessages {
293 + // we won't fail the decoding of the hex
294 + input, _ := hex.DecodeString(hexData)
295 + m := new(Msg)
296 + m.Unpack(input)
297 + //println(m.String())
298 + m.Compress = true
299 + lenComp := m.Len()
300 + b, _ := m.Pack()
301 + pacComp := len(b)
302 + m.Compress = false
303 + lenUnComp := m.Len()
304 + b, _ = m.Pack()
305 + pacUnComp := len(b)
306 + if pacComp+1 != lenComp {
307 + t.Errorf("msg.Len(compressed)=%d actual=%d for test %d", lenComp, pacComp, i)
308 + }
309 + if pacUnComp+1 != lenUnComp {
310 + t.Errorf("msg.Len(uncompressed)=%d actual=%d for test %d", lenUnComp, pacUnComp, i)
311 + }
312 + }
313 +}
314 +
315 +func TestMsgLengthCompressionMalformed(t *testing.T) {
316 + // SOA with empty hostmaster, which is illegal
317 + soa := &SOA{Hdr: RR_Header{Name: ".", Rrtype: TypeSOA, Class: ClassINET, Ttl: 12345},
318 + Ns: ".",
319 + Mbox: "",
320 + Serial: 0,
321 + Refresh: 28800,
322 + Retry: 7200,
323 + Expire: 604800,
324 + Minttl: 60}
325 + m := new(Msg)
326 + m.Compress = true
327 + m.Ns = []RR{soa}
328 + m.Len() // Should not crash.
329 +}
330 +
331 +func BenchmarkMsgLength(b *testing.B) {
332 + b.StopTimer()
333 + makeMsg := func(question string, ans, ns, e []RR) *Msg {
334 + msg := new(Msg)
335 + msg.SetQuestion(Fqdn(question), TypeANY)
336 + msg.Answer = append(msg.Answer, ans...)
337 + msg.Ns = append(msg.Ns, ns...)
338 + msg.Extra = append(msg.Extra, e...)
339 + msg.Compress = true
340 + return msg
341 + }
342 + name1 := "12345678901234567890123456789012345.12345678.123."
343 + rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
344 + msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
345 + b.StartTimer()
346 + for i := 0; i < b.N; i++ {
347 + msg.Len()
348 + }
349 +}
350 +
351 +func BenchmarkMsgLengthPack(b *testing.B) {
352 + makeMsg := func(question string, ans, ns, e []RR) *Msg {
353 + msg := new(Msg)
354 + msg.SetQuestion(Fqdn(question), TypeANY)
355 + msg.Answer = append(msg.Answer, ans...)
356 + msg.Ns = append(msg.Ns, ns...)
357 + msg.Extra = append(msg.Extra, e...)
358 + msg.Compress = true
359 + return msg
360 + }
361 + name1 := "12345678901234567890123456789012345.12345678.123."
362 + rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
363 + msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
364 + b.ResetTimer()
365 + for i := 0; i < b.N; i++ {
366 + _, _ = msg.Pack()
367 + }
368 +}
369 +
370 +func BenchmarkMsgPackBuffer(b *testing.B) {
371 + makeMsg := func(question string, ans, ns, e []RR) *Msg {
372 + msg := new(Msg)
373 + msg.SetQuestion(Fqdn(question), TypeANY)
374 + msg.Answer = append(msg.Answer, ans...)
375 + msg.Ns = append(msg.Ns, ns...)
376 + msg.Extra = append(msg.Extra, e...)
377 + msg.Compress = true
378 + return msg
379 + }
380 + name1 := "12345678901234567890123456789012345.12345678.123."
381 + rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
382 + msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
383 + buf := make([]byte, 512)
384 + b.ResetTimer()
385 + for i := 0; i < b.N; i++ {
386 + _, _ = msg.PackBuffer(buf)
387 + }
388 +}
389 +
390 +func BenchmarkMsgUnpack(b *testing.B) {
391 + makeMsg := func(question string, ans, ns, e []RR) *Msg {
392 + msg := new(Msg)
393 + msg.SetQuestion(Fqdn(question), TypeANY)
394 + msg.Answer = append(msg.Answer, ans...)
395 + msg.Ns = append(msg.Ns, ns...)
396 + msg.Extra = append(msg.Extra, e...)
397 + msg.Compress = true
398 + return msg
399 + }
400 + name1 := "12345678901234567890123456789012345.12345678.123."
401 + rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
402 + msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
403 + msg_buf, _ := msg.Pack()
404 + b.ResetTimer()
405 + for i := 0; i < b.N; i++ {
406 + _ = msg.Unpack(msg_buf)
407 + }
408 +}
409 +
410 +func BenchmarkPackDomainName(b *testing.B) {
411 + name1 := "12345678901234567890123456789012345.12345678.123."
412 + buf := make([]byte, len(name1)+1)
413 + b.ResetTimer()
414 + for i := 0; i < b.N; i++ {
415 + _, _ = PackDomainName(name1, buf, 0, nil, false)
416 + }
417 +}
418 +
419 +func BenchmarkUnpackDomainName(b *testing.B) {
420 + name1 := "12345678901234567890123456789012345.12345678.123."
421 + buf := make([]byte, len(name1)+1)
422 + _, _ = PackDomainName(name1, buf, 0, nil, false)
423 + b.ResetTimer()
424 + for i := 0; i < b.N; i++ {
425 + _, _, _ = UnpackDomainName(buf, 0)
426 + }
427 +}
428 +
429 +func BenchmarkUnpackDomainNameUnprintable(b *testing.B) {
430 + name1 := "\x02\x02\x02\x025\x02\x02\x02\x02.12345678.123."
431 + buf := make([]byte, len(name1)+1)
432 + _, _ = PackDomainName(name1, buf, 0, nil, false)
433 + b.ResetTimer()
434 + for i := 0; i < b.N; i++ {
435 + _, _, _ = UnpackDomainName(buf, 0)
436 + }
437 +}
438 +
439 +func TestToRFC3597(t *testing.T) {
440 + a, _ := NewRR("miek.nl. IN A 10.0.1.1")
441 + x := new(RFC3597)
442 + x.ToRFC3597(a)
443 + if x.String() != `miek.nl. 3600 CLASS1 TYPE1 \# 4 0a000101` {
444 + t.Fail()
445 + }
446 +}
447 +
448 +func TestNoRdataPack(t *testing.T) {
449 + data := make([]byte, 1024)
450 + for typ, fn := range typeToRR {
451 + if typ == TypeCAA {
452 + continue // TODO(miek): known omission
453 + }
454 + r := fn()
455 + *r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
456 + _, e := PackRR(r, data, 0, nil, false)
457 + if e != nil {
458 + t.Logf("failed to pack RR with zero rdata: %s: %s\n", TypeToString[typ], e.Error())
459 + t.Fail()
460 + }
461 + }
462 +}
463 +
464 +// TODO(miek): fix dns buffer too small errors this throws
465 +func TestNoRdataUnpack(t *testing.T) {
466 + data := make([]byte, 1024)
467 + for typ, fn := range typeToRR {
468 + if typ == TypeSOA || typ == TypeTSIG || typ == TypeWKS {
469 + // SOA, TSIG will not be seen (like this) in dyn. updates?
470 + // WKS is an bug, but...deprecated record.
471 + continue
472 + }
473 + r := fn()
474 + *r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
475 + off, e := PackRR(r, data, 0, nil, false)
476 + if e != nil {
477 + // Should always works, TestNoDataPack should have catched this
478 + continue
479 + }
480 + rr, _, e := UnpackRR(data[:off], 0)
481 + if e != nil {
482 + t.Logf("failed to unpack RR with zero rdata: %s: %s\n", TypeToString[typ], e.Error())
483 + t.Fail()
484 + }
485 + t.Logf("%s\n", rr)
486 + }
487 +}
488 +
489 +func TestRdataOverflow(t *testing.T) {
490 + rr := new(RFC3597)
491 + rr.Hdr.Name = "."
492 + rr.Hdr.Class = ClassINET
493 + rr.Hdr.Rrtype = 65280
494 + rr.Rdata = hex.EncodeToString(make([]byte, 0xFFFF))
495 + buf := make([]byte, 0xFFFF*2)
496 + if _, err := PackRR(rr, buf, 0, nil, false); err != nil {
497 + t.Fatalf("maximum size rrdata pack failed: %v", err)
498 + }
499 + rr.Rdata += "00"
500 + if _, err := PackRR(rr, buf, 0, nil, false); err != ErrRdata {
501 + t.Fatalf("oversize rrdata pack didn't return ErrRdata - instead: %v", err)
502 + }
503 +}
504 +
505 +func TestCopy(t *testing.T) {
506 + rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
507 + rr1 := Copy(rr)
508 + if rr.String() != rr1.String() {
509 + t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String())
510 + }
511 +}
512 +
513 +func TestPackIPSECKEY(t *testing.T) {
514 + tests := []string{
515 + "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
516 + "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
517 + "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
518 + "38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
519 + "0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
520 + }
521 + buf := make([]byte, 1024)
522 + for _, t1 := range tests {
523 + rr, _ := NewRR(t1)
524 + off, e := PackRR(rr, buf, 0, nil, false)
525 + if e != nil {
526 + t.Logf("failed to pack IPSECKEY %s: %s\n", e, t1)
527 + t.Fail()
528 + continue
529 + }
530 +
531 + rr, _, e = UnpackRR(buf[:off], 0)
532 + if e != nil {
533 + t.Logf("failed to unpack IPSECKEY %s: %s\n", e, t1)
534 + t.Fail()
535 + }
536 + t.Logf("%s\n", rr)
537 + }
538 +}
Godeps/_workspace/src/github.com/miekg/dns/dnssec.go new
+628
@@ -0,0 +1,628 @@
1 +// DNSSEC
2 +//
3 +// DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
4 +// uses public key cryptography to sign resource records. The
5 +// public keys are stored in DNSKEY records and the signatures in RRSIG records.
6 +//
7 +// Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
8 +// to an request.
9 +//
10 +// m := new(dns.Msg)
11 +// m.SetEdns0(4096, true)
12 +//
13 +// Signature generation, signature verification and key generation are all supported.
14 +package dns
15 +
16 +import (
17 + "bytes"
18 + "crypto"
19 + "crypto/dsa"
20 + "crypto/ecdsa"
21 + "crypto/elliptic"
22 + "crypto/md5"
23 + "crypto/rsa"
24 + "crypto/sha1"
25 + "crypto/sha256"
26 + "crypto/sha512"
27 + "encoding/hex"
28 + "hash"
29 + "io"
30 + "math/big"
31 + "sort"
32 + "strings"
33 + "time"
34 +)
35 +
36 +// DNSSEC encryption algorithm codes.
37 +const (
38 + _ uint8 = iota
39 + RSAMD5
40 + DH
41 + DSA
42 + _ // Skip 4, RFC 6725, section 2.1
43 + RSASHA1
44 + DSANSEC3SHA1
45 + RSASHA1NSEC3SHA1
46 + RSASHA256
47 + _ // Skip 9, RFC 6725, section 2.1
48 + RSASHA512
49 + _ // Skip 11, RFC 6725, section 2.1
50 + ECCGOST
51 + ECDSAP256SHA256
52 + ECDSAP384SHA384
53 + INDIRECT uint8 = 252
54 + PRIVATEDNS uint8 = 253 // Private (experimental keys)
55 + PRIVATEOID uint8 = 254
56 +)
57 +
58 +// DNSSEC hashing algorithm codes.
59 +const (
60 + _ uint8 = iota
61 + SHA1 // RFC 4034
62 + SHA256 // RFC 4509
63 + GOST94 // RFC 5933
64 + SHA384 // Experimental
65 + SHA512 // Experimental
66 +)
67 +
68 +// DNSKEY flag values.
69 +const (
70 + SEP = 1
71 + REVOKE = 1 << 7
72 + ZONE = 1 << 8
73 +)
74 +
75 +// The RRSIG needs to be converted to wireformat with some of
76 +// the rdata (the signature) missing. Use this struct to easy
77 +// the conversion (and re-use the pack/unpack functions).
78 +type rrsigWireFmt struct {
79 + TypeCovered uint16
80 + Algorithm uint8
81 + Labels uint8
82 + OrigTtl uint32
83 + Expiration uint32
84 + Inception uint32
85 + KeyTag uint16
86 + SignerName string `dns:"domain-name"`
87 + /* No Signature */
88 +}
89 +
90 +// Used for converting DNSKEY's rdata to wirefmt.
91 +type dnskeyWireFmt struct {
92 + Flags uint16
93 + Protocol uint8
94 + Algorithm uint8
95 + PublicKey string `dns:"base64"`
96 + /* Nothing is left out */
97 +}
98 +
99 +func divRoundUp(a, b int) int {
100 + return (a + b - 1) / b
101 +}
102 +
103 +// KeyTag calculates the keytag (or key-id) of the DNSKEY.
104 +func (k *DNSKEY) KeyTag() uint16 {
105 + if k == nil {
106 + return 0
107 + }
108 + var keytag int
109 + switch k.Algorithm {
110 + case RSAMD5:
111 + // Look at the bottom two bytes of the modules, which the last
112 + // item in the pubkey. We could do this faster by looking directly
113 + // at the base64 values. But I'm lazy.
114 + modulus, _ := fromBase64([]byte(k.PublicKey))
115 + if len(modulus) > 1 {
116 + x, _ := unpackUint16(modulus, len(modulus)-2)
117 + keytag = int(x)
118 + }
119 + default:
120 + keywire := new(dnskeyWireFmt)
121 + keywire.Flags = k.Flags
122 + keywire.Protocol = k.Protocol
123 + keywire.Algorithm = k.Algorithm
124 + keywire.PublicKey = k.PublicKey
125 + wire := make([]byte, DefaultMsgSize)
126 + n, err := PackStruct(keywire, wire, 0)
127 + if err != nil {
128 + return 0
129 + }
130 + wire = wire[:n]
131 + for i, v := range wire {
132 + if i&1 != 0 {
133 + keytag += int(v) // must be larger than uint32
134 + } else {
135 + keytag += int(v) << 8
136 + }
137 + }
138 + keytag += (keytag >> 16) & 0xFFFF
139 + keytag &= 0xFFFF
140 + }
141 + return uint16(keytag)
142 +}
143 +
144 +// ToDS converts a DNSKEY record to a DS record.
145 +func (k *DNSKEY) ToDS(h uint8) *DS {
146 + if k == nil {
147 + return nil
148 + }
149 + ds := new(DS)
150 + ds.Hdr.Name = k.Hdr.Name
151 + ds.Hdr.Class = k.Hdr.Class
152 + ds.Hdr.Rrtype = TypeDS
153 + ds.Hdr.Ttl = k.Hdr.Ttl
154 + ds.Algorithm = k.Algorithm
155 + ds.DigestType = h
156 + ds.KeyTag = k.KeyTag()
157 +
158 + keywire := new(dnskeyWireFmt)
159 + keywire.Flags = k.Flags
160 + keywire.Protocol = k.Protocol
161 + keywire.Algorithm = k.Algorithm
162 + keywire.PublicKey = k.PublicKey
163 + wire := make([]byte, DefaultMsgSize)
164 + n, err := PackStruct(keywire, wire, 0)
165 + if err != nil {
166 + return nil
167 + }
168 + wire = wire[:n]
169 +
170 + owner := make([]byte, 255)
171 + off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false)
172 + if err1 != nil {
173 + return nil
174 + }
175 + owner = owner[:off]
176 + // RFC4034:
177 + // digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
178 + // "|" denotes concatenation
179 + // DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
180 +
181 + // digest buffer
182 + digest := append(owner, wire...) // another copy
183 +
184 + switch h {
185 + case SHA1:
186 + s := sha1.New()
187 + io.WriteString(s, string(digest))
188 + ds.Digest = hex.EncodeToString(s.Sum(nil))
189 + case SHA256:
190 + s := sha256.New()
191 + io.WriteString(s, string(digest))
192 + ds.Digest = hex.EncodeToString(s.Sum(nil))
193 + case SHA384:
194 + s := sha512.New384()
195 + io.WriteString(s, string(digest))
196 + ds.Digest = hex.EncodeToString(s.Sum(nil))
197 + case GOST94:
198 + /* I have no clue */
199 + default:
200 + return nil
201 + }
202 + return ds
203 +}
204 +
205 +// Sign signs an RRSet. The signature needs to be filled in with
206 +// the values: Inception, Expiration, KeyTag, SignerName and Algorithm.
207 +// The rest is copied from the RRset. Sign returns true when the signing went OK,
208 +// otherwise false.
209 +// There is no check if RRSet is a proper (RFC 2181) RRSet.
210 +// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset
211 +// is used as the OrigTTL.
212 +func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
213 + if k == nil {
214 + return ErrPrivKey
215 + }
216 + // s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
217 + if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
218 + return ErrKey
219 + }
220 +
221 + rr.Hdr.Rrtype = TypeRRSIG
222 + rr.Hdr.Name = rrset[0].Header().Name
223 + rr.Hdr.Class = rrset[0].Header().Class
224 + if rr.OrigTtl == 0 { // If set don't override
225 + rr.OrigTtl = rrset[0].Header().Ttl
226 + }
227 + rr.TypeCovered = rrset[0].Header().Rrtype
228 + rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
229 +
230 + if strings.HasPrefix(rrset[0].Header().Name, "*") {
231 + rr.Labels-- // wildcard, remove from label count
232 + }
233 +
234 + sigwire := new(rrsigWireFmt)
235 + sigwire.TypeCovered = rr.TypeCovered
236 + sigwire.Algorithm = rr.Algorithm
237 + sigwire.Labels = rr.Labels
238 + sigwire.OrigTtl = rr.OrigTtl
239 + sigwire.Expiration = rr.Expiration
240 + sigwire.Inception = rr.Inception
241 + sigwire.KeyTag = rr.KeyTag
242 + // For signing, lowercase this name
243 + sigwire.SignerName = strings.ToLower(rr.SignerName)
244 +
245 + // Create the desired binary blob
246 + signdata := make([]byte, DefaultMsgSize)
247 + n, err := PackStruct(sigwire, signdata, 0)
248 + if err != nil {
249 + return err
250 + }
251 + signdata = signdata[:n]
252 + wire, err := rawSignatureData(rrset, rr)
253 + if err != nil {
254 + return err
255 + }
256 + signdata = append(signdata, wire...)
257 +
258 + var h hash.Hash
259 + switch rr.Algorithm {
260 + case DSA, DSANSEC3SHA1:
261 + // TODO: this seems bugged, will panic
262 + case RSASHA1, RSASHA1NSEC3SHA1:
263 + h = sha1.New()
264 + case RSASHA256, ECDSAP256SHA256:
265 + h = sha256.New()
266 + case ECDSAP384SHA384:
267 + h = sha512.New384()
268 + case RSASHA512:
269 + h = sha512.New()
270 + case RSAMD5:
271 + fallthrough // Deprecated in RFC 6725
272 + default:
273 + return ErrAlg
274 + }
275 +
276 + _, err = h.Write(signdata)
277 + if err != nil {
278 + return err
279 + }
280 + sighash := h.Sum(nil)
281 +
282 + signature, err := k.Sign(sighash, rr.Algorithm)
283 + if err != nil {
284 + return err
285 + }
286 + rr.Signature = toBase64(signature)
287 +
288 + return nil
289 +}
290 +
291 +// Verify validates an RRSet with the signature and key. This is only the
292 +// cryptographic test, the signature validity period must be checked separately.
293 +// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
294 +func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
295 + // First the easy checks
296 + if len(rrset) == 0 {
297 + return ErrRRset
298 + }
299 + if rr.KeyTag != k.KeyTag() {
300 + return ErrKey
301 + }
302 + if rr.Hdr.Class != k.Hdr.Class {
303 + return ErrKey
304 + }
305 + if rr.Algorithm != k.Algorithm {
306 + return ErrKey
307 + }
308 + if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
309 + return ErrKey
310 + }
311 + if k.Protocol != 3 {
312 + return ErrKey
313 + }
314 + for _, r := range rrset {
315 + if r.Header().Class != rr.Hdr.Class {
316 + return ErrRRset
317 + }
318 + if r.Header().Rrtype != rr.TypeCovered {
319 + return ErrRRset
320 + }
321 + }
322 + // RFC 4035 5.3.2. Reconstructing the Signed Data
323 + // Copy the sig, except the rrsig data
324 + sigwire := new(rrsigWireFmt)
325 + sigwire.TypeCovered = rr.TypeCovered
326 + sigwire.Algorithm = rr.Algorithm
327 + sigwire.Labels = rr.Labels
328 + sigwire.OrigTtl = rr.OrigTtl
329 + sigwire.Expiration = rr.Expiration
330 + sigwire.Inception = rr.Inception
331 + sigwire.KeyTag = rr.KeyTag
332 + sigwire.SignerName = strings.ToLower(rr.SignerName)
333 + // Create the desired binary blob
334 + signeddata := make([]byte, DefaultMsgSize)
335 + n, err := PackStruct(sigwire, signeddata, 0)
336 + if err != nil {
337 + return err
338 + }
339 + signeddata = signeddata[:n]
340 + wire, err := rawSignatureData(rrset, rr)
341 + if err != nil {
342 + return err
343 + }
344 + signeddata = append(signeddata, wire...)
345 +
346 + sigbuf := rr.sigBuf() // Get the binary signature data
347 + if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
348 + // TODO(mg)
349 + // remove the domain name and assume its our
350 + }
351 +
352 + switch rr.Algorithm {
353 + case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
354 + // TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
355 + pubkey := k.publicKeyRSA() // Get the key
356 + if pubkey == nil {
357 + return ErrKey
358 + }
359 + // Setup the hash as defined for this alg.
360 + var h hash.Hash
361 + var ch crypto.Hash
362 + switch rr.Algorithm {
363 + case RSAMD5:
364 + h = md5.New()
365 + ch = crypto.MD5
366 + case RSASHA1, RSASHA1NSEC3SHA1:
367 + h = sha1.New()
368 + ch = crypto.SHA1
369 + case RSASHA256:
370 + h = sha256.New()
371 + ch = crypto.SHA256
372 + case RSASHA512:
373 + h = sha512.New()
374 + ch = crypto.SHA512
375 + }
376 + io.WriteString(h, string(signeddata))
377 + sighash := h.Sum(nil)
378 + return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
379 + case ECDSAP256SHA256, ECDSAP384SHA384:
380 + pubkey := k.publicKeyECDSA()
381 + if pubkey == nil {
382 + return ErrKey
383 + }
384 + var h hash.Hash
385 + switch rr.Algorithm {
386 + case ECDSAP256SHA256:
387 + h = sha256.New()
388 + case ECDSAP384SHA384:
389 + h = sha512.New384()
390 + }
391 + io.WriteString(h, string(signeddata))
392 + sighash := h.Sum(nil)
393 + // Split sigbuf into the r and s coordinates
394 + r := big.NewInt(0)
395 + r.SetBytes(sigbuf[:len(sigbuf)/2])
396 + s := big.NewInt(0)
397 + s.SetBytes(sigbuf[len(sigbuf)/2:])
398 + if ecdsa.Verify(pubkey, sighash, r, s) {
399 + return nil
400 + }
401 + return ErrSig
402 + }
403 + // Unknown alg
404 + return ErrAlg
405 +}
406 +
407 +// ValidityPeriod uses RFC1982 serial arithmetic to calculate
408 +// if a signature period is valid. If t is the zero time, the
409 +// current time is taken other t is.
410 +func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
411 + var utc int64
412 + if t.IsZero() {
413 + utc = time.Now().UTC().Unix()
414 + } else {
415 + utc = t.UTC().Unix()
416 + }
417 + modi := (int64(rr.Inception) - utc) / year68
418 + mode := (int64(rr.Expiration) - utc) / year68
419 + ti := int64(rr.Inception) + (modi * year68)
420 + te := int64(rr.Expiration) + (mode * year68)
421 + return ti <= utc && utc <= te
422 +}
423 +
424 +// Return the signatures base64 encodedig sigdata as a byte slice.
425 +func (s *RRSIG) sigBuf() []byte {
426 + sigbuf, err := fromBase64([]byte(s.Signature))
427 + if err != nil {
428 + return nil
429 + }
430 + return sigbuf
431 +}
432 +
433 +// publicKeyRSA returns the RSA public key from a DNSKEY record.
434 +func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
435 + keybuf, err := fromBase64([]byte(k.PublicKey))
436 + if err != nil {
437 + return nil
438 + }
439 +
440 + // RFC 2537/3110, section 2. RSA Public KEY Resource Records
441 + // Length is in the 0th byte, unless its zero, then it
442 + // it in bytes 1 and 2 and its a 16 bit number
443 + explen := uint16(keybuf[0])
444 + keyoff := 1
445 + if explen == 0 {
446 + explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
447 + keyoff = 3
448 + }
449 + pubkey := new(rsa.PublicKey)
450 +
451 + pubkey.N = big.NewInt(0)
452 + shift := uint64((explen - 1) * 8)
453 + expo := uint64(0)
454 + for i := int(explen - 1); i > 0; i-- {
455 + expo += uint64(keybuf[keyoff+i]) << shift
456 + shift -= 8
457 + }
458 + // Remainder
459 + expo += uint64(keybuf[keyoff])
460 + if expo > 2<<31 {
461 + // Larger expo than supported.
462 + // println("dns: F5 primes (or larger) are not supported")
463 + return nil
464 + }
465 + pubkey.E = int(expo)
466 +
467 + pubkey.N.SetBytes(keybuf[keyoff+int(explen):])
468 + return pubkey
469 +}
470 +
471 +// publicKeyECDSA returns the Curve public key from the DNSKEY record.
472 +func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
473 + keybuf, err := fromBase64([]byte(k.PublicKey))
474 + if err != nil {
475 + return nil
476 + }
477 + pubkey := new(ecdsa.PublicKey)
478 + switch k.Algorithm {
479 + case ECDSAP256SHA256:
480 + pubkey.Curve = elliptic.P256()
481 + if len(keybuf) != 64 {
482 + // wrongly encoded key
483 + return nil
484 + }
485 + case ECDSAP384SHA384:
486 + pubkey.Curve = elliptic.P384()
487 + if len(keybuf) != 96 {
488 + // Wrongly encoded key
489 + return nil
490 + }
491 + }
492 + pubkey.X = big.NewInt(0)
493 + pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
494 + pubkey.Y = big.NewInt(0)
495 + pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
496 + return pubkey
497 +}
498 +
499 +func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
500 + keybuf, err := fromBase64([]byte(k.PublicKey))
501 + if err != nil {
502 + return nil
503 + }
504 + if len(keybuf) < 22 {
505 + return nil
506 + }
507 + t, keybuf := int(keybuf[0]), keybuf[1:]
508 + size := 64 + t*8
509 + q, keybuf := keybuf[:20], keybuf[20:]
510 + if len(keybuf) != 3*size {
511 + return nil
512 + }
513 + p, keybuf := keybuf[:size], keybuf[size:]
514 + g, y := keybuf[:size], keybuf[size:]
515 + pubkey := new(dsa.PublicKey)
516 + pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
517 + pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
518 + pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
519 + pubkey.Y = big.NewInt(0).SetBytes(y)
520 + return pubkey
521 +}
522 +
523 +type wireSlice [][]byte
524 +
525 +func (p wireSlice) Len() int { return len(p) }
526 +func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
527 +func (p wireSlice) Less(i, j int) bool {
528 + _, ioff, _ := UnpackDomainName(p[i], 0)
529 + _, joff, _ := UnpackDomainName(p[j], 0)
530 + return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0
531 +}
532 +
533 +// Return the raw signature data.
534 +func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
535 + wires := make(wireSlice, len(rrset))
536 + for i, r := range rrset {
537 + r1 := r.copy()
538 + r1.Header().Ttl = s.OrigTtl
539 + labels := SplitDomainName(r1.Header().Name)
540 + // 6.2. Canonical RR Form. (4) - wildcards
541 + if len(labels) > int(s.Labels) {
542 + // Wildcard
543 + r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
544 + }
545 + // RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
546 + r1.Header().Name = strings.ToLower(r1.Header().Name)
547 + // 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
548 + // NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
549 + // HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
550 + // SRV, DNAME, A6
551 + switch x := r1.(type) {
552 + case *NS:
553 + x.Ns = strings.ToLower(x.Ns)
554 + case *CNAME:
555 + x.Target = strings.ToLower(x.Target)
556 + case *SOA:
557 + x.Ns = strings.ToLower(x.Ns)
558 + x.Mbox = strings.ToLower(x.Mbox)
559 + case *MB:
560 + x.Mb = strings.ToLower(x.Mb)
561 + case *MG:
562 + x.Mg = strings.ToLower(x.Mg)
563 + case *MR:
564 + x.Mr = strings.ToLower(x.Mr)
565 + case *PTR:
566 + x.Ptr = strings.ToLower(x.Ptr)
567 + case *MINFO:
568 + x.Rmail = strings.ToLower(x.Rmail)
569 + x.Email = strings.ToLower(x.Email)
570 + case *MX:
571 + x.Mx = strings.ToLower(x.Mx)
572 + case *NAPTR:
573 + x.Replacement = strings.ToLower(x.Replacement)
574 + case *KX:
575 + x.Exchanger = strings.ToLower(x.Exchanger)
576 + case *SRV:
577 + x.Target = strings.ToLower(x.Target)
578 + case *DNAME:
579 + x.Target = strings.ToLower(x.Target)
580 + }
581 + // 6.2. Canonical RR Form. (5) - origTTL
582 + wire := make([]byte, r1.len()+1) // +1 to be safe(r)
583 + off, err1 := PackRR(r1, wire, 0, nil, false)
584 + if err1 != nil {
585 + return nil, err1
586 + }
587 + wire = wire[:off]
588 + wires[i] = wire
589 + }
590 + sort.Sort(wires)
591 + for _, wire := range wires {
592 + buf = append(buf, wire...)
593 + }
594 + return buf, nil
595 +}
596 +
597 +// Map for algorithm names.
598 +var AlgorithmToString = map[uint8]string{
599 + RSAMD5: "RSAMD5",
600 + DH: "DH",
601 + DSA: "DSA",
602 + RSASHA1: "RSASHA1",
603 + DSANSEC3SHA1: "DSA-NSEC3-SHA1",
604 + RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
605 + RSASHA256: "RSASHA256",
606 + RSASHA512: "RSASHA512",
607 + ECCGOST: "ECC-GOST",
608 + ECDSAP256SHA256: "ECDSAP256SHA256",
609 + ECDSAP384SHA384: "ECDSAP384SHA384",
610 + INDIRECT: "INDIRECT",
611 + PRIVATEDNS: "PRIVATEDNS",
612 + PRIVATEOID: "PRIVATEOID",
613 +}
614 +
615 +// Map of algorithm strings.
616 +var StringToAlgorithm = reverseInt8(AlgorithmToString)
617 +
618 +// Map for hash names.
619 +var HashToString = map[uint8]string{
620 + SHA1: "SHA1",
621 + SHA256: "SHA256",
622 + GOST94: "GOST94",
623 + SHA384: "SHA384",
624 + SHA512: "SHA512",
625 +}
626 +
627 +// Map of hash strings.
628 +var StringToHash = reverseInt8(HashToString)
Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go new
+155
@@ -0,0 +1,155 @@
1 +package dns
2 +
3 +import (
4 + "crypto/dsa"
5 + "crypto/ecdsa"
6 + "crypto/elliptic"
7 + "crypto/rand"
8 + "crypto/rsa"
9 + "math/big"
10 +)
11 +
12 +// Generate generates a DNSKEY of the given bit size.
13 +// The public part is put inside the DNSKEY record.
14 +// The Algorithm in the key must be set as this will define
15 +// what kind of DNSKEY will be generated.
16 +// The ECDSA algorithms imply a fixed keysize, in that case
17 +// bits should be set to the size of the algorithm.
18 +func (r *DNSKEY) Generate(bits int) (PrivateKey, error) {
19 + switch r.Algorithm {
20 + case DSA, DSANSEC3SHA1:
21 + if bits != 1024 {
22 + return nil, ErrKeySize
23 + }
24 + case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
25 + if bits < 512 || bits > 4096 {
26 + return nil, ErrKeySize
27 + }
28 + case RSASHA512:
29 + if bits < 1024 || bits > 4096 {
30 + return nil, ErrKeySize
31 + }
32 + case ECDSAP256SHA256:
33 + if bits != 256 {
34 + return nil, ErrKeySize
35 + }
36 + case ECDSAP384SHA384:
37 + if bits != 384 {
38 + return nil, ErrKeySize
39 + }
40 + }
41 +
42 + switch r.Algorithm {
43 + case DSA, DSANSEC3SHA1:
44 + params := new(dsa.Parameters)
45 + if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
46 + return nil, err
47 + }
48 + priv := new(dsa.PrivateKey)
49 + priv.PublicKey.Parameters = *params
50 + err := dsa.GenerateKey(priv, rand.Reader)
51 + if err != nil {
52 + return nil, err
53 + }
54 + r.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
55 + return (*DSAPrivateKey)(priv), nil
56 + case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
57 + priv, err := rsa.GenerateKey(rand.Reader, bits)
58 + if err != nil {
59 + return nil, err
60 + }
61 + r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
62 + return (*RSAPrivateKey)(priv), nil
63 + case ECDSAP256SHA256, ECDSAP384SHA384:
64 + var c elliptic.Curve
65 + switch r.Algorithm {
66 + case ECDSAP256SHA256:
67 + c = elliptic.P256()
68 + case ECDSAP384SHA384:
69 + c = elliptic.P384()
70 + }
71 + priv, err := ecdsa.GenerateKey(c, rand.Reader)
72 + if err != nil {
73 + return nil, err
74 + }
75 + r.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
76 + return (*ECDSAPrivateKey)(priv), nil
77 + default:
78 + return nil, ErrAlg
79 + }
80 +}
81 +
82 +// Set the public key (the value E and N)
83 +func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
84 + if _E == 0 || _N == nil {
85 + return false
86 + }
87 + buf := exponentToBuf(_E)
88 + buf = append(buf, _N.Bytes()...)
89 + k.PublicKey = toBase64(buf)
90 + return true
91 +}
92 +
93 +// Set the public key for Elliptic Curves
94 +func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
95 + if _X == nil || _Y == nil {
96 + return false
97 + }
98 + var intlen int
99 + switch k.Algorithm {
100 + case ECDSAP256SHA256:
101 + intlen = 32
102 + case ECDSAP384SHA384:
103 + intlen = 48
104 + }
105 + k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
106 + return true
107 +}
108 +
109 +// Set the public key for DSA
110 +func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
111 + if _Q == nil || _P == nil || _G == nil || _Y == nil {
112 + return false
113 + }
114 + buf := dsaToBuf(_Q, _P, _G, _Y)
115 + k.PublicKey = toBase64(buf)
116 + return true
117 +}
118 +
119 +// Set the public key (the values E and N) for RSA
120 +// RFC 3110: Section 2. RSA Public KEY Resource Records
121 +func exponentToBuf(_E int) []byte {
122 + var buf []byte
123 + i := big.NewInt(int64(_E))
124 + if len(i.Bytes()) < 256 {
125 + buf = make([]byte, 1)
126 + buf[0] = uint8(len(i.Bytes()))
127 + } else {
128 + buf = make([]byte, 3)
129 + buf[0] = 0
130 + buf[1] = uint8(len(i.Bytes()) >> 8)
131 + buf[2] = uint8(len(i.Bytes()))
132 + }
133 + buf = append(buf, i.Bytes()...)
134 + return buf
135 +}
136 +
137 +// Set the public key for X and Y for Curve. The two
138 +// values are just concatenated.
139 +func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
140 + buf := intToBytes(_X, intlen)
141 + buf = append(buf, intToBytes(_Y, intlen)...)
142 + return buf
143 +}
144 +
145 +// Set the public key for X and Y for Curve. The two
146 +// values are just concatenated.
147 +func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
148 + t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
149 + buf := []byte{byte(t)}
150 + buf = append(buf, intToBytes(_Q, 20)...)
151 + buf = append(buf, intToBytes(_P, 64+t*8)...)
152 + buf = append(buf, intToBytes(_G, 64+t*8)...)
153 + buf = append(buf, intToBytes(_Y, 64+t*8)...)
154 + return buf
155 +}
Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go new
+241
@@ -0,0 +1,241 @@
1 +package dns
2 +
3 +import (
4 + "crypto/dsa"
5 + "crypto/ecdsa"
6 + "crypto/rsa"
7 + "io"
8 + "math/big"
9 + "strings"
10 +)
11 +
12 +func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
13 + if s[len(s)-1] != '\n' { // We need a closing newline
14 + return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
15 + }
16 + return k.ReadPrivateKey(strings.NewReader(s), "")
17 +}
18 +
19 +// ReadPrivateKey reads a private key from the io.Reader q. The string file is
20 +// only used in error reporting.
21 +// The public key must be known, because some cryptographic algorithms embed
22 +// the public inside the privatekey.
23 +func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
24 + m, e := parseKey(q, file)
25 + if m == nil {
26 + return nil, e
27 + }
28 + if _, ok := m["private-key-format"]; !ok {
29 + return nil, ErrPrivKey
30 + }
31 + if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" {
32 + return nil, ErrPrivKey
33 + }
34 + // TODO(mg): check if the pubkey matches the private key
35 + switch m["algorithm"] {
36 + case "3 (DSA)":
37 + priv, e := readPrivateKeyDSA(m)
38 + if e != nil {
39 + return nil, e
40 + }
41 + pub := k.publicKeyDSA()
42 + if pub == nil {
43 + return nil, ErrKey
44 + }
45 + priv.PublicKey = *pub
46 + return (*DSAPrivateKey)(priv), e
47 + case "1 (RSAMD5)":
48 + fallthrough
49 + case "5 (RSASHA1)":
50 + fallthrough
51 + case "7 (RSASHA1NSEC3SHA1)":
52 + fallthrough
53 + case "8 (RSASHA256)":
54 + fallthrough
55 + case "10 (RSASHA512)":
56 + priv, e := readPrivateKeyRSA(m)
57 + if e != nil {
58 + return nil, e
59 + }
60 + pub := k.publicKeyRSA()
61 + if pub == nil {
62 + return nil, ErrKey
63 + }
64 + priv.PublicKey = *pub
65 + return (*RSAPrivateKey)(priv), e
66 + case "12 (ECC-GOST)":
67 + return nil, ErrPrivKey
68 + case "13 (ECDSAP256SHA256)":
69 + fallthrough
70 + case "14 (ECDSAP384SHA384)":
71 + priv, e := readPrivateKeyECDSA(m)
72 + if e != nil {
73 + return nil, e
74 + }
75 + pub := k.publicKeyECDSA()
76 + if pub == nil {
77 + return nil, ErrKey
78 + }
79 + priv.PublicKey = *pub
80 + return (*ECDSAPrivateKey)(priv), e
81 + default:
82 + return nil, ErrPrivKey
83 + }
84 +}
85 +
86 +// Read a private key (file) string and create a public key. Return the private key.
87 +func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
88 + p := new(rsa.PrivateKey)
89 + p.Primes = []*big.Int{nil, nil}
90 + for k, v := range m {
91 + switch k {
92 + case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
93 + v1, err := fromBase64([]byte(v))
94 + if err != nil {
95 + return nil, err
96 + }
97 + switch k {
98 + case "modulus":
99 + p.PublicKey.N = big.NewInt(0)
100 + p.PublicKey.N.SetBytes(v1)
101 + case "publicexponent":
102 + i := big.NewInt(0)
103 + i.SetBytes(v1)
104 + p.PublicKey.E = int(i.Int64()) // int64 should be large enough
105 + case "privateexponent":
106 + p.D = big.NewInt(0)
107 + p.D.SetBytes(v1)
108 + case "prime1":
109 + p.Primes[0] = big.NewInt(0)
110 + p.Primes[0].SetBytes(v1)
111 + case "prime2":
112 + p.Primes[1] = big.NewInt(0)
113 + p.Primes[1].SetBytes(v1)
114 + }
115 + case "exponent1", "exponent2", "coefficient":
116 + // not used in Go (yet)
117 + case "created", "publish", "activate":
118 + // not used in Go (yet)
119 + }
120 + }
121 + return p, nil
122 +}
123 +
124 +func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
125 + p := new(dsa.PrivateKey)
126 + p.X = big.NewInt(0)
127 + for k, v := range m {
128 + switch k {
129 + case "private_value(x)":
130 + v1, err := fromBase64([]byte(v))
131 + if err != nil {
132 + return nil, err
133 + }
134 + p.X.SetBytes(v1)
135 + case "created", "publish", "activate":
136 + /* not used in Go (yet) */
137 + }
138 + }
139 + return p, nil
140 +}
141 +
142 +func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
143 + p := new(ecdsa.PrivateKey)
144 + p.D = big.NewInt(0)
145 + // TODO: validate that the required flags are present
146 + for k, v := range m {
147 + switch k {
148 + case "privatekey":
149 + v1, err := fromBase64([]byte(v))
150 + if err != nil {
151 + return nil, err
152 + }
153 + p.D.SetBytes(v1)
154 + case "created", "publish", "activate":
155 + /* not used in Go (yet) */
156 + }
157 + }
158 + return p, nil
159 +}
160 +
161 +// parseKey reads a private key from r. It returns a map[string]string,
162 +// with the key-value pairs, or an error when the file is not correct.
163 +func parseKey(r io.Reader, file string) (map[string]string, error) {
164 + s := scanInit(r)
165 + m := make(map[string]string)
166 + c := make(chan lex)
167 + k := ""
168 + // Start the lexer
169 + go klexer(s, c)
170 + for l := range c {
171 + // It should alternate
172 + switch l.value {
173 + case _KEY:
174 + k = l.token
175 + case _VALUE:
176 + if k == "" {
177 + return nil, &ParseError{file, "no private key seen", l}
178 + }
179 + //println("Setting", strings.ToLower(k), "to", l.token, "b")
180 + m[strings.ToLower(k)] = l.token
181 + k = ""
182 + }
183 + }
184 + return m, nil
185 +}
186 +
187 +// klexer scans the sourcefile and returns tokens on the channel c.
188 +func klexer(s *scan, c chan lex) {
189 + var l lex
190 + str := "" // Hold the current read text
191 + commt := false
192 + key := true
193 + x, err := s.tokenText()
194 + defer close(c)
195 + for err == nil {
196 + l.column = s.position.Column
197 + l.line = s.position.Line
198 + switch x {
199 + case ':':
200 + if commt {
201 + break
202 + }
203 + l.token = str
204 + if key {
205 + l.value = _KEY
206 + c <- l
207 + // Next token is a space, eat it
208 + s.tokenText()
209 + key = false
210 + str = ""
211 + } else {
212 + l.value = _VALUE
213 + }
214 + case ';':
215 + commt = true
216 + case '\n':
217 + if commt {
218 + // Reset a comment
219 + commt = false
220 + }
221 + l.value = _VALUE
222 + l.token = str
223 + c <- l
224 + str = ""
225 + commt = false
226 + key = true
227 + default:
228 + if commt {
229 + break
230 + }
231 + str += string(x)
232 + }
233 + x, err = s.tokenText()
234 + }
235 + if len(str) > 0 {
236 + // Send remainder
237 + l.token = str
238 + l.value = _VALUE
239 + c <- l
240 + }
241 +}
Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go new
+143
@@ -0,0 +1,143 @@
1 +package dns
2 +
3 +import (
4 + "crypto"
5 + "crypto/dsa"
6 + "crypto/ecdsa"
7 + "crypto/rand"
8 + "crypto/rsa"
9 + "math/big"
10 + "strconv"
11 +)
12 +
13 +const _FORMAT = "Private-key-format: v1.3\n"
14 +
15 +type PrivateKey interface {
16 + Sign([]byte, uint8) ([]byte, error)
17 + String(uint8) string
18 +}
19 +
20 +// PrivateKeyString converts a PrivateKey to a string. This string has the same
21 +// format as the private-key-file of BIND9 (Private-key-format: v1.3).
22 +// It needs some info from the key (the algorithm), so its a method of the
23 +// DNSKEY and calls PrivateKey.String(alg).
24 +func (r *DNSKEY) PrivateKeyString(p PrivateKey) string {
25 + return p.String(r.Algorithm)
26 +}
27 +
28 +type RSAPrivateKey rsa.PrivateKey
29 +
30 +func (p *RSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
31 + var hash crypto.Hash
32 + switch alg {
33 + case RSASHA1, RSASHA1NSEC3SHA1:
34 + hash = crypto.SHA1
35 + case RSASHA256:
36 + hash = crypto.SHA256
37 + case RSASHA512:
38 + hash = crypto.SHA512
39 + default:
40 + return nil, ErrAlg
41 + }
42 + return rsa.SignPKCS1v15(nil, (*rsa.PrivateKey)(p), hash, hashed)
43 +}
44 +
45 +func (p *RSAPrivateKey) String(alg uint8) string {
46 + algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
47 + modulus := toBase64(p.PublicKey.N.Bytes())
48 + e := big.NewInt(int64(p.PublicKey.E))
49 + publicExponent := toBase64(e.Bytes())
50 + privateExponent := toBase64(p.D.Bytes())
51 + prime1 := toBase64(p.Primes[0].Bytes())
52 + prime2 := toBase64(p.Primes[1].Bytes())
53 + // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
54 + // and from: http://code.google.com/p/go/issues/detail?id=987
55 + one := big.NewInt(1)
56 + p_1 := big.NewInt(0).Sub(p.Primes[0], one)
57 + q_1 := big.NewInt(0).Sub(p.Primes[1], one)
58 + exp1 := big.NewInt(0).Mod(p.D, p_1)
59 + exp2 := big.NewInt(0).Mod(p.D, q_1)
60 + coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
61 +
62 + exponent1 := toBase64(exp1.Bytes())
63 + exponent2 := toBase64(exp2.Bytes())
64 + coefficient := toBase64(coeff.Bytes())
65 +
66 + return _FORMAT +
67 + "Algorithm: " + algorithm + "\n" +
68 + "Modulus: " + modulus + "\n" +
69 + "PublicExponent: " + publicExponent + "\n" +
70 + "PrivateExponent: " + privateExponent + "\n" +
71 + "Prime1: " + prime1 + "\n" +
72 + "Prime2: " + prime2 + "\n" +
73 + "Exponent1: " + exponent1 + "\n" +
74 + "Exponent2: " + exponent2 + "\n" +
75 + "Coefficient: " + coefficient + "\n"
76 +}
77 +
78 +type ECDSAPrivateKey ecdsa.PrivateKey
79 +
80 +func (p *ECDSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
81 + var intlen int
82 + switch alg {
83 + case ECDSAP256SHA256:
84 + intlen = 32
85 + case ECDSAP384SHA384:
86 + intlen = 48
87 + default:
88 + return nil, ErrAlg
89 + }
90 + r1, s1, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(p), hashed)
91 + if err != nil {
92 + return nil, err
93 + }
94 + signature := intToBytes(r1, intlen)
95 + signature = append(signature, intToBytes(s1, intlen)...)
96 + return signature, nil
97 +}
98 +
99 +func (p *ECDSAPrivateKey) String(alg uint8) string {
100 + algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
101 + var intlen int
102 + switch alg {
103 + case ECDSAP256SHA256:
104 + intlen = 32
105 + case ECDSAP384SHA384:
106 + intlen = 48
107 + }
108 + private := toBase64(intToBytes(p.D, intlen))
109 + return _FORMAT +
110 + "Algorithm: " + algorithm + "\n" +
111 + "PrivateKey: " + private + "\n"
112 +}
113 +
114 +type DSAPrivateKey dsa.PrivateKey
115 +
116 +func (p *DSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
117 + r1, s1, err := dsa.Sign(rand.Reader, (*dsa.PrivateKey)(p), hashed)
118 + if err != nil {
119 + return nil, err
120 + }
121 + t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
122 + signature := []byte{byte(t)}
123 + signature = append(signature, intToBytes(r1, 20)...)
124 + signature = append(signature, intToBytes(s1, 20)...)
125 + return signature, nil
126 +}
127 +
128 +func (p *DSAPrivateKey) String(alg uint8) string {
129 + algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
130 + T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
131 + prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
132 + subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
133 + base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
134 + priv := toBase64(intToBytes(p.X, 20))
135 + pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
136 + return _FORMAT +
137 + "Algorithm: " + algorithm + "\n" +
138 + "Prime(p): " + prime + "\n" +
139 + "Subprime(q): " + subprime + "\n" +
140 + "Base(g): " + base + "\n" +
141 + "Private_value(x): " + priv + "\n" +
142 + "Public_value(y): " + pub + "\n"
143 +}
Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go new
+680
@@ -0,0 +1,680 @@
1 +package dns
2 +
3 +import (
4 + "reflect"
5 + "strings"
6 + "testing"
7 + "time"
8 +)
9 +
10 +func getKey() *DNSKEY {
11 + key := new(DNSKEY)
12 + key.Hdr.Name = "miek.nl."
13 + key.Hdr.Class = ClassINET
14 + key.Hdr.Ttl = 14400
15 + key.Flags = 256
16 + key.Protocol = 3
17 + key.Algorithm = RSASHA256
18 + key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
19 + return key
20 +}
21 +
22 +func getSoa() *SOA {
23 + soa := new(SOA)
24 + soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
25 + soa.Ns = "open.nlnetlabs.nl."
26 + soa.Mbox = "miekg.atoom.net."
27 + soa.Serial = 1293945905
28 + soa.Refresh = 14400
29 + soa.Retry = 3600
30 + soa.Expire = 604800
31 + soa.Minttl = 86400
32 + return soa
33 +}
34 +
35 +func TestGenerateEC(t *testing.T) {
36 + if testing.Short() {
37 + t.Skip("skipping test in short mode.")
38 + }
39 + key := new(DNSKEY)
40 + key.Hdr.Rrtype = TypeDNSKEY
41 + key.Hdr.Name = "miek.nl."
42 + key.Hdr.Class = ClassINET
43 + key.Hdr.Ttl = 14400
44 + key.Flags = 256
45 + key.Protocol = 3
46 + key.Algorithm = ECDSAP256SHA256
47 + privkey, _ := key.Generate(256)
48 + t.Logf("%s\n", key.String())
49 + t.Logf("%s\n", key.PrivateKeyString(privkey))
50 +}
51 +
52 +func TestGenerateDSA(t *testing.T) {
53 + if testing.Short() {
54 + t.Skip("skipping test in short mode.")
55 + }
56 + key := new(DNSKEY)
57 + key.Hdr.Rrtype = TypeDNSKEY
58 + key.Hdr.Name = "miek.nl."
59 + key.Hdr.Class = ClassINET
60 + key.Hdr.Ttl = 14400
61 + key.Flags = 256
62 + key.Protocol = 3
63 + key.Algorithm = DSA
64 + privkey, _ := key.Generate(1024)
65 + t.Logf("%s\n", key.String())
66 + t.Logf("%s\n", key.PrivateKeyString(privkey))
67 +}
68 +
69 +func TestGenerateRSA(t *testing.T) {
70 + if testing.Short() {
71 + t.Skip("skipping test in short mode.")
72 + }
73 + key := new(DNSKEY)
74 + key.Hdr.Rrtype = TypeDNSKEY
75 + key.Hdr.Name = "miek.nl."
76 + key.Hdr.Class = ClassINET
77 + key.Hdr.Ttl = 14400
78 + key.Flags = 256
79 + key.Protocol = 3
80 + key.Algorithm = RSASHA256
81 + privkey, _ := key.Generate(1024)
82 + t.Logf("%s\n", key.String())
83 + t.Logf("%s\n", key.PrivateKeyString(privkey))
84 +}
85 +
86 +func TestSecure(t *testing.T) {
87 + soa := getSoa()
88 +
89 + sig := new(RRSIG)
90 + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
91 + sig.TypeCovered = TypeSOA
92 + sig.Algorithm = RSASHA256
93 + sig.Labels = 2
94 + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
95 + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
96 + sig.OrigTtl = 14400
97 + sig.KeyTag = 12051
98 + sig.SignerName = "miek.nl."
99 + sig.Signature = "oMCbslaAVIp/8kVtLSms3tDABpcPRUgHLrOR48OOplkYo+8TeEGWwkSwaz/MRo2fB4FxW0qj/hTlIjUGuACSd+b1wKdH5GvzRJc2pFmxtCbm55ygAh4EUL0F6U5cKtGJGSXxxg6UFCQ0doJCmiGFa78LolaUOXImJrk6AFrGa0M="
100 +
101 + key := new(DNSKEY)
102 + key.Hdr.Name = "miek.nl."
103 + key.Hdr.Class = ClassINET
104 + key.Hdr.Ttl = 14400
105 + key.Flags = 256
106 + key.Protocol = 3
107 + key.Algorithm = RSASHA256
108 + key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
109 +
110 + // It should validate. Period is checked seperately, so this will keep on working
111 + if sig.Verify(key, []RR{soa}) != nil {
112 + t.Log("failure to validate")
113 + t.Fail()
114 + }
115 +}
116 +
117 +func TestSignature(t *testing.T) {
118 + sig := new(RRSIG)
119 + sig.Hdr.Name = "miek.nl."
120 + sig.Hdr.Class = ClassINET
121 + sig.Hdr.Ttl = 3600
122 + sig.TypeCovered = TypeDNSKEY
123 + sig.Algorithm = RSASHA1
124 + sig.Labels = 2
125 + sig.OrigTtl = 4000
126 + sig.Expiration = 1000 //Thu Jan 1 02:06:40 CET 1970
127 + sig.Inception = 800 //Thu Jan 1 01:13:20 CET 1970
128 + sig.KeyTag = 34641
129 + sig.SignerName = "miek.nl."
130 + sig.Signature = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
131 +
132 + // Should not be valid
133 + if sig.ValidityPeriod(time.Now()) {
134 + t.Log("should not be valid")
135 + t.Fail()
136 + }
137 +
138 + sig.Inception = 315565800 //Tue Jan 1 10:10:00 CET 1980
139 + sig.Expiration = 4102477800 //Fri Jan 1 10:10:00 CET 2100
140 + if !sig.ValidityPeriod(time.Now()) {
141 + t.Log("should be valid")
142 + t.Fail()
143 + }
144 +}
145 +
146 +func TestSignVerify(t *testing.T) {
147 + // The record we want to sign
148 + soa := new(SOA)
149 + soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
150 + soa.Ns = "open.nlnetlabs.nl."
151 + soa.Mbox = "miekg.atoom.net."
152 + soa.Serial = 1293945905
153 + soa.Refresh = 14400
154 + soa.Retry = 3600
155 + soa.Expire = 604800
156 + soa.Minttl = 86400
157 +
158 + soa1 := new(SOA)
159 + soa1.Hdr = RR_Header{"*.miek.nl.", TypeSOA, ClassINET, 14400, 0}
160 + soa1.Ns = "open.nlnetlabs.nl."
161 + soa1.Mbox = "miekg.atoom.net."
162 + soa1.Serial = 1293945905
163 + soa1.Refresh = 14400
164 + soa1.Retry = 3600
165 + soa1.Expire = 604800
166 + soa1.Minttl = 86400
167 +
168 + srv := new(SRV)
169 + srv.Hdr = RR_Header{"srv.miek.nl.", TypeSRV, ClassINET, 14400, 0}
170 + srv.Port = 1000
171 + srv.Weight = 800
172 + srv.Target = "web1.miek.nl."
173 +
174 + // With this key
175 + key := new(DNSKEY)
176 + key.Hdr.Rrtype = TypeDNSKEY
177 + key.Hdr.Name = "miek.nl."
178 + key.Hdr.Class = ClassINET
179 + key.Hdr.Ttl = 14400
180 + key.Flags = 256
181 + key.Protocol = 3
182 + key.Algorithm = RSASHA256
183 + privkey, _ := key.Generate(512)
184 +
185 + // Fill in the values of the Sig, before signing
186 + sig := new(RRSIG)
187 + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
188 + sig.TypeCovered = soa.Hdr.Rrtype
189 + sig.Labels = uint8(CountLabel(soa.Hdr.Name)) // works for all 3
190 + sig.OrigTtl = soa.Hdr.Ttl
191 + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
192 + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
193 + sig.KeyTag = key.KeyTag() // Get the keyfrom the Key
194 + sig.SignerName = key.Hdr.Name
195 + sig.Algorithm = RSASHA256
196 +
197 + for _, r := range []RR{soa, soa1, srv} {
198 + if sig.Sign(privkey, []RR{r}) != nil {
199 + t.Log("failure to sign the record")
200 + t.Fail()
201 + continue
202 + }
203 + if sig.Verify(key, []RR{r}) != nil {
204 + t.Log("failure to validate")
205 + t.Fail()
206 + continue
207 + }
208 + t.Logf("validated: %s\n", r.Header().Name)
209 + }
210 +}
211 +
212 +func Test65534(t *testing.T) {
213 + t6 := new(RFC3597)
214 + t6.Hdr = RR_Header{"miek.nl.", 65534, ClassINET, 14400, 0}
215 + t6.Rdata = "505D870001"
216 + key := new(DNSKEY)
217 + key.Hdr.Name = "miek.nl."
218 + key.Hdr.Rrtype = TypeDNSKEY
219 + key.Hdr.Class = ClassINET
220 + key.Hdr.Ttl = 14400
221 + key.Flags = 256
222 + key.Protocol = 3
223 + key.Algorithm = RSASHA256
224 + privkey, _ := key.Generate(1024)
225 +
226 + sig := new(RRSIG)
227 + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
228 + sig.TypeCovered = t6.Hdr.Rrtype
229 + sig.Labels = uint8(CountLabel(t6.Hdr.Name))
230 + sig.OrigTtl = t6.Hdr.Ttl
231 + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
232 + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
233 + sig.KeyTag = key.KeyTag()
234 + sig.SignerName = key.Hdr.Name
235 + sig.Algorithm = RSASHA256
236 + if err := sig.Sign(privkey, []RR{t6}); err != nil {
237 + t.Log(err)
238 + t.Log("failure to sign the TYPE65534 record")
239 + t.Fail()
240 + }
241 + if err := sig.Verify(key, []RR{t6}); err != nil {
242 + t.Log(err)
243 + t.Log("failure to validate")
244 + t.Fail()
245 + } else {
246 + t.Logf("validated: %s\n", t6.Header().Name)
247 + }
248 +}
249 +
250 +func TestDnskey(t *testing.T) {
251 + pubkey, err := ReadRR(strings.NewReader(`
252 +miek.nl. IN DNSKEY 256 3 10 AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL ;{id = 5240 (zsk), size = 1024b}
253 +`), "Kmiek.nl.+010+05240.key")
254 + if err != nil {
255 + t.Fatal(err)
256 + }
257 + privStr := `Private-key-format: v1.3
258 +Algorithm: 10 (RSASHA512)
259 +Modulus: m4wK7YV26AeROtdiCXmqLG9wPDVoMOW8vjr/EkpscEAdjXp81RvZvrlzCSjYmz9onFRgltmTl3AINnFh+t9tlW0M9C5zejxBoKFXELv8ljPYAdz2oe+pDWPhWsfvVFYg2VCjpViPM38EakyE5mhk4TDOnUd+w4TeU1hyhZTWyYs=
260 +PublicExponent: AQAB
261 +PrivateExponent: UfCoIQ/Z38l8vB6SSqOI/feGjHEl/fxIPX4euKf0D/32k30fHbSaNFrFOuIFmWMB3LimWVEs6u3dpbB9CQeCVg7hwU5puG7OtuiZJgDAhNeOnxvo5btp4XzPZrJSxR4WNQnwIiYWbl0aFlL1VGgHC/3By89ENZyWaZcMLW4KGWE=
262 +Prime1: yxwC6ogAu8aVcDx2wg1V0b5M5P6jP8qkRFVMxWNTw60Vkn+ECvw6YAZZBHZPaMyRYZLzPgUlyYRd0cjupy4+fQ==
263 +Prime2: xA1bF8M0RTIQ6+A11AoVG6GIR/aPGg5sogRkIZ7ID/sF6g9HMVU/CM2TqVEBJLRPp73cv6ZeC3bcqOCqZhz+pw==
264 +Exponent1: xzkblyZ96bGYxTVZm2/vHMOXswod4KWIyMoOepK6B/ZPcZoIT6omLCgtypWtwHLfqyCz3MK51Nc0G2EGzg8rFQ==
265 +Exponent2: Pu5+mCEb7T5F+kFNZhQadHUklt0JUHbi3hsEvVoHpEGSw3BGDQrtIflDde0/rbWHgDPM4WQY+hscd8UuTXrvLw==
266 +Coefficient: UuRoNqe7YHnKmQzE6iDWKTMIWTuoqqrFAmXPmKQnC+Y+BQzOVEHUo9bXdDnoI9hzXP1gf8zENMYwYLeWpuYlFQ==
267 +`
268 + privkey, err := pubkey.(*DNSKEY).ReadPrivateKey(strings.NewReader(privStr),
269 + "Kmiek.nl.+010+05240.private")
270 + if err != nil {
271 + t.Fatal(err)
272 + }
273 + if pubkey.(*DNSKEY).PublicKey != "AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL" {
274 + t.Log("pubkey is not what we've read")
275 + t.Fail()
276 + }
277 + if pubkey.(*DNSKEY).PrivateKeyString(privkey) != privStr {
278 + t.Log("privkey is not what we've read")
279 + t.Logf("%v", pubkey.(*DNSKEY).PrivateKeyString(privkey))
280 + t.Fail()
281 + }
282 +}
283 +
284 +func TestTag(t *testing.T) {
285 + key := new(DNSKEY)
286 + key.Hdr.Name = "miek.nl."
287 + key.Hdr.Rrtype = TypeDNSKEY
288 + key.Hdr.Class = ClassINET
289 + key.Hdr.Ttl = 3600
290 + key.Flags = 256
291 + key.Protocol = 3
292 + key.Algorithm = RSASHA256
293 + key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
294 +
295 + tag := key.KeyTag()
296 + if tag != 12051 {
297 + t.Logf("wrong key tag: %d for key %v\n", tag, key)
298 + t.Fail()
299 + }
300 +}
301 +
302 +func TestKeyRSA(t *testing.T) {
303 + if testing.Short() {
304 + t.Skip("skipping test in short mode.")
305 + }
306 + key := new(DNSKEY)
307 + key.Hdr.Name = "miek.nl."
308 + key.Hdr.Rrtype = TypeDNSKEY
309 + key.Hdr.Class = ClassINET
310 + key.Hdr.Ttl = 3600
311 + key.Flags = 256
312 + key.Protocol = 3
313 + key.Algorithm = RSASHA256
314 + priv, _ := key.Generate(2048)
315 +
316 + soa := new(SOA)
317 + soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
318 + soa.Ns = "open.nlnetlabs.nl."
319 + soa.Mbox = "miekg.atoom.net."
320 + soa.Serial = 1293945905
321 + soa.Refresh = 14400
322 + soa.Retry = 3600
323 + soa.Expire = 604800
324 + soa.Minttl = 86400
325 +
326 + sig := new(RRSIG)
327 + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
328 + sig.TypeCovered = TypeSOA
329 + sig.Algorithm = RSASHA256
330 + sig.Labels = 2
331 + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
332 + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
333 + sig.OrigTtl = soa.Hdr.Ttl
334 + sig.KeyTag = key.KeyTag()
335 + sig.SignerName = key.Hdr.Name
336 +
337 + if err := sig.Sign(priv, []RR{soa}); err != nil {
338 + t.Logf("failed to sign")
339 + t.Fail()
340 + return
341 + }
342 + if err := sig.Verify(key, []RR{soa}); err != nil {
343 + t.Logf("failed to verify")
344 + t.Fail()
345 + }
346 +}
347 +
348 +func TestKeyToDS(t *testing.T) {
349 + key := new(DNSKEY)
350 + key.Hdr.Name = "miek.nl."
351 + key.Hdr.Rrtype = TypeDNSKEY
352 + key.Hdr.Class = ClassINET
353 + key.Hdr.Ttl = 3600
354 + key.Flags = 256
355 + key.Protocol = 3
356 + key.Algorithm = RSASHA256
357 + key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
358 +
359 + ds := key.ToDS(SHA1)
360 + if strings.ToUpper(ds.Digest) != "B5121BDB5B8D86D0CC5FFAFBAAABE26C3E20BAC1" {
361 + t.Logf("wrong DS digest for SHA1\n%v\n", ds)
362 + t.Fail()
363 + }
364 +}
365 +
366 +func TestSignRSA(t *testing.T) {
367 + pub := "miek.nl. IN DNSKEY 256 3 5 AwEAAb+8lGNCxJgLS8rYVer6EnHVuIkQDghdjdtewDzU3G5R7PbMbKVRvH2Ma7pQyYceoaqWZQirSj72euPWfPxQnMy9ucCylA+FuH9cSjIcPf4PqJfdupHk9X6EBYjxrCLY4p1/yBwgyBIRJtZtAqM3ceAH2WovEJD6rTtOuHo5AluJ"
368 +
369 + priv := `Private-key-format: v1.3
370 +Algorithm: 5 (RSASHA1)
371 +Modulus: v7yUY0LEmAtLythV6voScdW4iRAOCF2N217APNTcblHs9sxspVG8fYxrulDJhx6hqpZlCKtKPvZ649Z8/FCczL25wLKUD4W4f1xKMhw9/g+ol926keT1foQFiPGsItjinX/IHCDIEhEm1m0Cozdx4AfZai8QkPqtO064ejkCW4k=
372 +PublicExponent: AQAB
373 +PrivateExponent: YPwEmwjk5HuiROKU4xzHQ6l1hG8Iiha4cKRG3P5W2b66/EN/GUh07ZSf0UiYB67o257jUDVEgwCuPJz776zfApcCB4oGV+YDyEu7Hp/rL8KcSN0la0k2r9scKwxTp4BTJT23zyBFXsV/1wRDK1A5NxsHPDMYi2SoK63Enm/1ptk=
374 +Prime1: /wjOG+fD0ybNoSRn7nQ79udGeR1b0YhUA5mNjDx/x2fxtIXzygYk0Rhx9QFfDy6LOBvz92gbNQlzCLz3DJt5hw==
375 +Prime2: wHZsJ8OGhkp5p3mrJFZXMDc2mbYusDVTA+t+iRPdS797Tj0pjvU2HN4vTnTj8KBQp6hmnY7dLp9Y1qserySGbw==
376 +Exponent1: N0A7FsSRIg+IAN8YPQqlawoTtG1t1OkJ+nWrurPootScApX6iMvn8fyvw3p2k51rv84efnzpWAYiC8SUaQDNxQ==
377 +Exponent2: SvuYRaGyvo0zemE3oS+WRm2scxR8eiA8WJGeOc+obwOKCcBgeZblXzfdHGcEC1KaOcetOwNW/vwMA46lpLzJNw==
378 +Coefficient: 8+7ZN/JgByqv0NfULiFKTjtyegUcijRuyij7yNxYbCBneDvZGxJwKNi4YYXWx743pcAj4Oi4Oh86gcmxLs+hGw==
379 +Created: 20110302104537
380 +Publish: 20110302104537
381 +Activate: 20110302104537`
382 +
383 + xk, _ := NewRR(pub)
384 + k := xk.(*DNSKEY)
385 + p, err := k.NewPrivateKey(priv)
386 + if err != nil {
387 + t.Logf("%v\n", err)
388 + t.Fail()
389 + }
390 + switch priv := p.(type) {
391 + case *RSAPrivateKey:
392 + if 65537 != priv.PublicKey.E {
393 + t.Log("exponenent should be 65537")
394 + t.Fail()
395 + }
396 + default:
397 + t.Logf("we should have read an RSA key: %v", priv)
398 + t.Fail()
399 + }
400 + if k.KeyTag() != 37350 {
401 + t.Logf("%d %v\n", k.KeyTag(), k)
402 + t.Log("keytag should be 37350")
403 + t.Fail()
404 + }
405 +
406 + soa := new(SOA)
407 + soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
408 + soa.Ns = "open.nlnetlabs.nl."
409 + soa.Mbox = "miekg.atoom.net."
410 + soa.Serial = 1293945905
411 + soa.Refresh = 14400
412 + soa.Retry = 3600
413 + soa.Expire = 604800
414 + soa.Minttl = 86400
415 +
416 + sig := new(RRSIG)
417 + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
418 + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
419 + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
420 + sig.KeyTag = k.KeyTag()
421 + sig.SignerName = k.Hdr.Name
422 + sig.Algorithm = k.Algorithm
423 +
424 + sig.Sign(p, []RR{soa})
425 + if sig.Signature != "D5zsobpQcmMmYsUMLxCVEtgAdCvTu8V/IEeP4EyLBjqPJmjt96bwM9kqihsccofA5LIJ7DN91qkCORjWSTwNhzCv7bMyr2o5vBZElrlpnRzlvsFIoAZCD9xg6ZY7ZyzUJmU6IcTwG4v3xEYajcpbJJiyaw/RqR90MuRdKPiBzSo=" {
426 + t.Log("signature is not correct")
427 + t.Logf("%v\n", sig)
428 + t.Fail()
429 + }
430 +}
431 +
432 +func TestSignVerifyECDSA(t *testing.T) {
433 + pub := `example.net. 3600 IN DNSKEY 257 3 14 (
434 + xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1
435 + w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8
436 + /uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )`
437 + priv := `Private-key-format: v1.2
438 +Algorithm: 14 (ECDSAP384SHA384)
439 +PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
440 +
441 + eckey, err := NewRR(pub)
442 + if err != nil {
443 + t.Fatal(err.Error())
444 + }
445 + privkey, err := eckey.(*DNSKEY).NewPrivateKey(priv)
446 + if err != nil {
447 + t.Fatal(err.Error())
448 + }
449 + // TODO: Create seperate test for this
450 + ds := eckey.(*DNSKEY).ToDS(SHA384)
451 + if ds.KeyTag != 10771 {
452 + t.Fatal("wrong keytag on DS")
453 + }
454 + if ds.Digest != "72d7b62976ce06438e9c0bf319013cf801f09ecc84b8d7e9495f27e305c6a9b0563a9b5f4d288405c3008a946df983d6" {
455 + t.Fatal("wrong DS Digest")
456 + }
457 + a, _ := NewRR("www.example.net. 3600 IN A 192.0.2.1")
458 + sig := new(RRSIG)
459 + sig.Hdr = RR_Header{"example.net.", TypeRRSIG, ClassINET, 14400, 0}
460 + sig.Expiration, _ = StringToTime("20100909102025")
461 + sig.Inception, _ = StringToTime("20100812102025")
462 + sig.KeyTag = eckey.(*DNSKEY).KeyTag()
463 + sig.SignerName = eckey.(*DNSKEY).Hdr.Name
464 + sig.Algorithm = eckey.(*DNSKEY).Algorithm
465 +
466 + if sig.Sign(privkey, []RR{a}) != nil {
467 + t.Fatal("failure to sign the record")
468 + }
469 +
470 + if e := sig.Verify(eckey.(*DNSKEY), []RR{a}); e != nil {
471 + t.Logf("\n%s\n%s\n%s\n\n%s\n\n",
472 + eckey.(*DNSKEY).String(),
473 + a.String(),
474 + sig.String(),
475 + eckey.(*DNSKEY).PrivateKeyString(privkey),
476 + )
477 +
478 + t.Fatalf("failure to validate: %s", e.Error())
479 + }
480 +}
481 +
482 +func TestSignVerifyECDSA2(t *testing.T) {
483 + srv1, err := NewRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
484 + if err != nil {
485 + t.Fatalf(err.Error())
486 + }
487 + srv := srv1.(*SRV)
488 +
489 + // With this key
490 + key := new(DNSKEY)
491 + key.Hdr.Rrtype = TypeDNSKEY
492 + key.Hdr.Name = "miek.nl."
493 + key.Hdr.Class = ClassINET
494 + key.Hdr.Ttl = 14400
495 + key.Flags = 256
496 + key.Protocol = 3
497 + key.Algorithm = ECDSAP256SHA256
498 + privkey, err := key.Generate(256)
499 + if err != nil {
500 + t.Fatal("failure to generate key")
501 + }
502 +
503 + // Fill in the values of the Sig, before signing
504 + sig := new(RRSIG)
505 + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
506 + sig.TypeCovered = srv.Hdr.Rrtype
507 + sig.Labels = uint8(CountLabel(srv.Hdr.Name)) // works for all 3
508 + sig.OrigTtl = srv.Hdr.Ttl
509 + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
510 + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
511 + sig.KeyTag = key.KeyTag() // Get the keyfrom the Key
512 + sig.SignerName = key.Hdr.Name
513 + sig.Algorithm = ECDSAP256SHA256
514 +
515 + if sig.Sign(privkey, []RR{srv}) != nil {
516 + t.Fatal("failure to sign the record")
517 + }
518 +
519 + err = sig.Verify(key, []RR{srv})
520 + if err != nil {
521 + t.Logf("\n%s\n%s\n%s\n\n%s\n\n",
522 + key.String(),
523 + srv.String(),
524 + sig.String(),
525 + key.PrivateKeyString(privkey),
526 + )
527 +
528 + t.Fatal("Failure to validate:", err)
529 + }
530 +}
531 +
532 +// Here the test vectors from the relevant RFCs are checked.
533 +// rfc6605 6.1
534 +func TestRFC6605P256(t *testing.T) {
535 + exDNSKEY := `example.net. 3600 IN DNSKEY 257 3 13 (
536 + GojIhhXUN/u4v54ZQqGSnyhWJwaubCvTmeexv7bR6edb
537 + krSqQpF64cYbcB7wNcP+e+MAnLr+Wi9xMWyQLc8NAA== )`
538 + exPriv := `Private-key-format: v1.2
539 +Algorithm: 13 (ECDSAP256SHA256)
540 +PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
541 + rrDNSKEY, err := NewRR(exDNSKEY)
542 + if err != nil {
543 + t.Fatal(err.Error())
544 + }
545 + priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
546 + if err != nil {
547 + t.Fatal(err.Error())
548 + }
549 +
550 + exDS := `example.net. 3600 IN DS 55648 13 2 (
551 + b4c8c1fe2e7477127b27115656ad6256f424625bf5c1
552 + e2770ce6d6e37df61d17 )`
553 + rrDS, err := NewRR(exDS)
554 + if err != nil {
555 + t.Fatal(err.Error())
556 + }
557 + ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA256)
558 + if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
559 + t.Errorf("DS record differs:\n%v\n%v\n", ourDS, rrDS.(*DS))
560 + }
561 +
562 + exA := `www.example.net. 3600 IN A 192.0.2.1`
563 + exRRSIG := `www.example.net. 3600 IN RRSIG A 13 3 3600 (
564 + 20100909100439 20100812100439 55648 example.net.
565 + qx6wLYqmh+l9oCKTN6qIc+bw6ya+KJ8oMz0YP107epXA
566 + yGmt+3SNruPFKG7tZoLBLlUzGGus7ZwmwWep666VCw== )`
567 + rrA, err := NewRR(exA)
568 + if err != nil {
569 + t.Fatal(err.Error())
570 + }
571 + rrRRSIG, err := NewRR(exRRSIG)
572 + if err != nil {
573 + t.Fatal(err.Error())
574 + }
575 + if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
576 + t.Errorf("Failure to validate the spec RRSIG: %v", err)
577 + }
578 +
579 + ourRRSIG := &RRSIG{
580 + Hdr: RR_Header{
581 + Ttl: rrA.Header().Ttl,
582 + },
583 + KeyTag: rrDNSKEY.(*DNSKEY).KeyTag(),
584 + SignerName: rrDNSKEY.(*DNSKEY).Hdr.Name,
585 + Algorithm: rrDNSKEY.(*DNSKEY).Algorithm,
586 + }
587 + ourRRSIG.Expiration, _ = StringToTime("20100909100439")
588 + ourRRSIG.Inception, _ = StringToTime("20100812100439")
589 + err = ourRRSIG.Sign(priv, []RR{rrA})
590 + if err != nil {
591 + t.Fatal(err.Error())
592 + }
593 +
594 + if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
595 + t.Errorf("Failure to validate our RRSIG: %v", err)
596 + }
597 +
598 + // Signatures are randomized
599 + rrRRSIG.(*RRSIG).Signature = ""
600 + ourRRSIG.Signature = ""
601 + if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) {
602 + t.Fatalf("RRSIG record differs:\n%v\n%v\n", ourRRSIG, rrRRSIG.(*RRSIG))
603 + }
604 +}
605 +
606 +// rfc6605 6.2
607 +func TestRFC6605P384(t *testing.T) {
608 + exDNSKEY := `example.net. 3600 IN DNSKEY 257 3 14 (
609 + xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1
610 + w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8
611 + /uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )`
612 + exPriv := `Private-key-format: v1.2
613 +Algorithm: 14 (ECDSAP384SHA384)
614 +PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
615 + rrDNSKEY, err := NewRR(exDNSKEY)
616 + if err != nil {
617 + t.Fatal(err.Error())
618 + }
619 + priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
620 + if err != nil {
621 + t.Fatal(err.Error())
622 + }
623 +
624 + exDS := `example.net. 3600 IN DS 10771 14 4 (
625 + 72d7b62976ce06438e9c0bf319013cf801f09ecc84b8
626 + d7e9495f27e305c6a9b0563a9b5f4d288405c3008a94
627 + 6df983d6 )`
628 + rrDS, err := NewRR(exDS)
629 + if err != nil {
630 + t.Fatal(err.Error())
631 + }
632 + ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA384)
633 + if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
634 + t.Fatalf("DS record differs:\n%v\n%v\n", ourDS, rrDS.(*DS))
635 + }
636 +
637 + exA := `www.example.net. 3600 IN A 192.0.2.1`
638 + exRRSIG := `www.example.net. 3600 IN RRSIG A 14 3 3600 (
639 + 20100909102025 20100812102025 10771 example.net.
640 + /L5hDKIvGDyI1fcARX3z65qrmPsVz73QD1Mr5CEqOiLP
641 + 95hxQouuroGCeZOvzFaxsT8Glr74hbavRKayJNuydCuz
642 + WTSSPdz7wnqXL5bdcJzusdnI0RSMROxxwGipWcJm )`
643 + rrA, err := NewRR(exA)
644 + if err != nil {
645 + t.Fatal(err.Error())
646 + }
647 + rrRRSIG, err := NewRR(exRRSIG)
648 + if err != nil {
649 + t.Fatal(err.Error())
650 + }
651 + if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
652 + t.Errorf("Failure to validate the spec RRSIG: %v", err)
653 + }
654 +
655 + ourRRSIG := &RRSIG{
656 + Hdr: RR_Header{
657 + Ttl: rrA.Header().Ttl,
658 + },
659 + KeyTag: rrDNSKEY.(*DNSKEY).KeyTag(),
660 + SignerName: rrDNSKEY.(*DNSKEY).Hdr.Name,
661 + Algorithm: rrDNSKEY.(*DNSKEY).Algorithm,
662 + }
663 + ourRRSIG.Expiration, _ = StringToTime("20100909102025")
664 + ourRRSIG.Inception, _ = StringToTime("20100812102025")
665 + err = ourRRSIG.Sign(priv, []RR{rrA})
666 + if err != nil {
667 + t.Fatal(err.Error())
668 + }
669 +
670 + if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
671 + t.Errorf("Failure to validate our RRSIG: %v", err)
672 + }
673 +
674 + // Signatures are randomized
675 + rrRRSIG.(*RRSIG).Signature = ""
676 + ourRRSIG.Signature = ""
677 + if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) {
678 + t.Fatalf("RRSIG record differs:\n%v\n%v\n", ourRRSIG, rrRRSIG.(*RRSIG))
679 + }
680 +}
Godeps/_workspace/src/github.com/miekg/dns/dyn_test.go new
+3
@@ -0,0 +1,3 @@
1 +package dns
2 +
3 +// Find better solution
Godeps/_workspace/src/github.com/miekg/dns/edns.go new
+501
@@ -0,0 +1,501 @@
1 +// EDNS0
2 +//
3 +// EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
4 +// by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
5 +// abused.
6 +// Basic use pattern for creating an (empty) OPT RR:
7 +//
8 +// o := new(dns.OPT)
9 +// o.Hdr.Name = "." // MUST be the root zone, per definition.
10 +// o.Hdr.Rrtype = dns.TypeOPT
11 +//
12 +// The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
13 +// interfaces. Currently only a few have been standardized: EDNS0_NSID
14 +// (RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
15 +// that these options may be combined in an OPT RR.
16 +// Basic use pattern for a server to check if (and which) options are set:
17 +//
18 +// // o is a dns.OPT
19 +// for _, s := range o.Option {
20 +// switch e := s.(type) {
21 +// case *dns.EDNS0_NSID:
22 +// // do stuff with e.Nsid
23 +// case *dns.EDNS0_SUBNET:
24 +// // access e.Family, e.Address, etc.
25 +// }
26 +// }
27 +package dns
28 +
29 +import (
30 + "encoding/hex"
31 + "errors"
32 + "net"
33 + "strconv"
34 +)
35 +
36 +// EDNS0 Option codes.
37 +const (
38 + EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
39 + EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
40 + EDNS0NSID = 0x3 // nsid (RFC5001)
41 + EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
42 + EDNS0DHU = 0x6 // DS Hash Understood
43 + EDNS0N3U = 0x7 // NSEC3 Hash Understood
44 + EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
45 + EDNS0EXPIRE = 0x9 // EDNS0 expire
46 + EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
47 + _DO = 1 << 15 // dnssec ok
48 +)
49 +
50 +type OPT struct {
51 + Hdr RR_Header
52 + Option []EDNS0 `dns:"opt"`
53 +}
54 +
55 +func (rr *OPT) Header() *RR_Header {
56 + return &rr.Hdr
57 +}
58 +
59 +func (rr *OPT) String() string {
60 + s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
61 + if rr.Do() {
62 + s += "flags: do; "
63 + } else {
64 + s += "flags: ; "
65 + }
66 + s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
67 +
68 + for _, o := range rr.Option {
69 + switch o.(type) {
70 + case *EDNS0_NSID:
71 + s += "\n; NSID: " + o.String()
72 + h, e := o.pack()
73 + var r string
74 + if e == nil {
75 + for _, c := range h {
76 + r += "(" + string(c) + ")"
77 + }
78 + s += " " + r
79 + }
80 + case *EDNS0_SUBNET:
81 + s += "\n; SUBNET: " + o.String()
82 + if o.(*EDNS0_SUBNET).DraftOption {
83 + s += " (draft)"
84 + }
85 + case *EDNS0_UL:
86 + s += "\n; UPDATE LEASE: " + o.String()
87 + case *EDNS0_LLQ:
88 + s += "\n; LONG LIVED QUERIES: " + o.String()
89 + case *EDNS0_DAU:
90 + s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
91 + case *EDNS0_DHU:
92 + s += "\n; DS HASH UNDERSTOOD: " + o.String()
93 + case *EDNS0_N3U:
94 + s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
95 + }
96 + }
97 + return s
98 +}
99 +
100 +func (rr *OPT) len() int {
101 + l := rr.Hdr.len()
102 + for i := 0; i < len(rr.Option); i++ {
103 + lo, _ := rr.Option[i].pack()
104 + l += 2 + len(lo)
105 + }
106 + return l
107 +}
108 +
109 +func (rr *OPT) copy() RR {
110 + return &OPT{*rr.Hdr.copyHeader(), rr.Option}
111 +}
112 +
113 +// return the old value -> delete SetVersion?
114 +
115 +// Version returns the EDNS version used. Only zero is defined.
116 +func (rr *OPT) Version() uint8 {
117 + return uint8((rr.Hdr.Ttl & 0x00FF0000) >> 16)
118 +}
119 +
120 +// SetVersion sets the version of EDNS. This is usually zero.
121 +func (rr *OPT) SetVersion(v uint8) {
122 + rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16)
123 +}
124 +
125 +// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
126 +func (rr *OPT) ExtendedRcode() uint8 {
127 + return uint8((rr.Hdr.Ttl & 0xFF000000) >> 24)
128 +}
129 +
130 +// SetExtendedRcode sets the EDNS extended RCODE field.
131 +func (rr *OPT) SetExtendedRcode(v uint8) {
132 + rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24)
133 +}
134 +
135 +// UDPSize returns the UDP buffer size.
136 +func (rr *OPT) UDPSize() uint16 {
137 + return rr.Hdr.Class
138 +}
139 +
140 +// SetUDPSize sets the UDP buffer size.
141 +func (rr *OPT) SetUDPSize(size uint16) {
142 + rr.Hdr.Class = size
143 +}
144 +
145 +// Do returns the value of the DO (DNSSEC OK) bit.
146 +func (rr *OPT) Do() bool {
147 + return rr.Hdr.Ttl&_DO == _DO
148 +}
149 +
150 +// SetDo sets the DO (DNSSEC OK) bit.
151 +func (rr *OPT) SetDo() {
152 + rr.Hdr.Ttl |= _DO
153 +}
154 +
155 +// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to
156 +// it.
157 +type EDNS0 interface {
158 + // Option returns the option code for the option.
159 + Option() uint16
160 + // pack returns the bytes of the option data.
161 + pack() ([]byte, error)
162 + // unpack sets the data as found in the buffer. Is also sets
163 + // the length of the slice as the length of the option data.
164 + unpack([]byte) error
165 + // String returns the string representation of the option.
166 + String() string
167 +}
168 +
169 +// The nsid EDNS0 option is used to retrieve a nameserver
170 +// identifier. When sending a request Nsid must be set to the empty string
171 +// The identifier is an opaque string encoded as hex.
172 +// Basic use pattern for creating an nsid option:
173 +//
174 +// o := new(dns.OPT)
175 +// o.Hdr.Name = "."
176 +// o.Hdr.Rrtype = dns.TypeOPT
177 +// e := new(dns.EDNS0_NSID)
178 +// e.Code = dns.EDNS0NSID
179 +// e.Nsid = "AA"
180 +// o.Option = append(o.Option, e)
181 +type EDNS0_NSID struct {
182 + Code uint16 // Always EDNS0NSID
183 + Nsid string // This string needs to be hex encoded
184 +}
185 +
186 +func (e *EDNS0_NSID) pack() ([]byte, error) {
187 + h, err := hex.DecodeString(e.Nsid)
188 + if err != nil {
189 + return nil, err
190 + }
191 + return h, nil
192 +}
193 +
194 +func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
195 +func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
196 +func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
197 +
198 +// The subnet EDNS0 option is used to give the remote nameserver
199 +// an idea of where the client lives. It can then give back a different
200 +// answer depending on the location or network topology.
201 +// Basic use pattern for creating an subnet option:
202 +//
203 +// o := new(dns.OPT)
204 +// o.Hdr.Name = "."
205 +// o.Hdr.Rrtype = dns.TypeOPT
206 +// e := new(dns.EDNS0_SUBNET)
207 +// e.Code = dns.EDNS0SUBNET
208 +// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
209 +// e.NetMask = 32 // 32 for IPV4, 128 for IPv6
210 +// e.SourceScope = 0
211 +// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
212 +// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
213 +// o.Option = append(o.Option, e)
214 +type EDNS0_SUBNET struct {
215 + Code uint16 // Always EDNS0SUBNET
216 + Family uint16 // 1 for IP, 2 for IP6
217 + SourceNetmask uint8
218 + SourceScope uint8
219 + Address net.IP
220 + DraftOption bool // Set to true if using the old (0x50fa) option code
221 +}
222 +
223 +func (e *EDNS0_SUBNET) Option() uint16 {
224 + if e.DraftOption {
225 + return EDNS0SUBNETDRAFT
226 + }
227 + return EDNS0SUBNET
228 +}
229 +
230 +func (e *EDNS0_SUBNET) pack() ([]byte, error) {
231 + b := make([]byte, 4)
232 + b[0], b[1] = packUint16(e.Family)
233 + b[2] = e.SourceNetmask
234 + b[3] = e.SourceScope
235 + switch e.Family {
236 + case 1:
237 + if e.SourceNetmask > net.IPv4len*8 {
238 + return nil, errors.New("dns: bad netmask")
239 + }
240 + ip := make([]byte, net.IPv4len)
241 + a := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
242 + for i := 0; i < net.IPv4len; i++ {
243 + if i+1 > len(e.Address) {
244 + break
245 + }
246 + ip[i] = a[i]
247 + }
248 + needLength := e.SourceNetmask / 8
249 + if e.SourceNetmask%8 > 0 {
250 + needLength++
251 + }
252 + ip = ip[:needLength]
253 + b = append(b, ip...)
254 + case 2:
255 + if e.SourceNetmask > net.IPv6len*8 {
256 + return nil, errors.New("dns: bad netmask")
257 + }
258 + ip := make([]byte, net.IPv6len)
259 + a := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
260 + for i := 0; i < net.IPv6len; i++ {
261 + if i+1 > len(e.Address) {
262 + break
263 + }
264 + ip[i] = a[i]
265 + }
266 + needLength := e.SourceNetmask / 8
267 + if e.SourceNetmask%8 > 0 {
268 + needLength++
269 + }
270 + ip = ip[:needLength]
271 + b = append(b, ip...)
272 + default:
273 + return nil, errors.New("dns: bad address family")
274 + }
275 + return b, nil
276 +}
277 +
278 +func (e *EDNS0_SUBNET) unpack(b []byte) error {
279 + lb := len(b)
280 + if lb < 4 {
281 + return ErrBuf
282 + }
283 + e.Family, _ = unpackUint16(b, 0)
284 + e.SourceNetmask = b[2]
285 + e.SourceScope = b[3]
286 + switch e.Family {
287 + case 1:
288 + addr := make([]byte, 4)
289 + for i := 0; i < int(e.SourceNetmask/8); i++ {
290 + if i >= len(addr) || 4+i >= len(b) {
291 + return ErrBuf
292 + }
293 + addr[i] = b[4+i]
294 + }
295 + e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
296 + case 2:
297 + addr := make([]byte, 16)
298 + for i := 0; i < int(e.SourceNetmask/8); i++ {
299 + if i >= len(addr) || 4+i >= len(b) {
300 + return ErrBuf
301 + }
302 + addr[i] = b[4+i]
303 + }
304 + e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
305 + addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
306 + addr[11], addr[12], addr[13], addr[14], addr[15]}
307 + }
308 + return nil
309 +}
310 +
311 +func (e *EDNS0_SUBNET) String() (s string) {
312 + if e.Address == nil {
313 + s = "<nil>"
314 + } else if e.Address.To4() != nil {
315 + s = e.Address.String()
316 + } else {
317 + s = "[" + e.Address.String() + "]"
318 + }
319 + s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
320 + return
321 +}
322 +
323 +// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set
324 +// an expiration on an update RR. This is helpful for clients that cannot clean
325 +// up after themselves. This is a draft RFC and more information can be found at
326 +// http://files.dns-sd.org/draft-sekar-dns-ul.txt
327 +//
328 +// o := new(dns.OPT)
329 +// o.Hdr.Name = "."
330 +// o.Hdr.Rrtype = dns.TypeOPT
331 +// e := new(dns.EDNS0_UL)
332 +// e.Code = dns.EDNS0UL
333 +// e.Lease = 120 // in seconds
334 +// o.Option = append(o.Option, e)
335 +type EDNS0_UL struct {
336 + Code uint16 // Always EDNS0UL
337 + Lease uint32
338 +}
339 +
340 +func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
341 +func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
342 +
343 +// Copied: http://golang.org/src/pkg/net/dnsmsg.go
344 +func (e *EDNS0_UL) pack() ([]byte, error) {
345 + b := make([]byte, 4)
346 + b[0] = byte(e.Lease >> 24)
347 + b[1] = byte(e.Lease >> 16)
348 + b[2] = byte(e.Lease >> 8)
349 + b[3] = byte(e.Lease)
350 + return b, nil
351 +}
352 +
353 +func (e *EDNS0_UL) unpack(b []byte) error {
354 + if len(b) < 4 {
355 + return ErrBuf
356 + }
357 + e.Lease = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
358 + return nil
359 +}
360 +
361 +// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
362 +// Implemented for completeness, as the EDNS0 type code is assigned.
363 +type EDNS0_LLQ struct {
364 + Code uint16 // Always EDNS0LLQ
365 + Version uint16
366 + Opcode uint16
367 + Error uint16
368 + Id uint64
369 + LeaseLife uint32
370 +}
371 +
372 +func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
373 +
374 +func (e *EDNS0_LLQ) pack() ([]byte, error) {
375 + b := make([]byte, 18)
376 + b[0], b[1] = packUint16(e.Version)
377 + b[2], b[3] = packUint16(e.Opcode)
378 + b[4], b[5] = packUint16(e.Error)
379 + b[6] = byte(e.Id >> 56)
380 + b[7] = byte(e.Id >> 48)
381 + b[8] = byte(e.Id >> 40)
382 + b[9] = byte(e.Id >> 32)
383 + b[10] = byte(e.Id >> 24)
384 + b[11] = byte(e.Id >> 16)
385 + b[12] = byte(e.Id >> 8)
386 + b[13] = byte(e.Id)
387 + b[14] = byte(e.LeaseLife >> 24)
388 + b[15] = byte(e.LeaseLife >> 16)
389 + b[16] = byte(e.LeaseLife >> 8)
390 + b[17] = byte(e.LeaseLife)
391 + return b, nil
392 +}
393 +
394 +func (e *EDNS0_LLQ) unpack(b []byte) error {
395 + if len(b) < 18 {
396 + return ErrBuf
397 + }
398 + e.Version, _ = unpackUint16(b, 0)
399 + e.Opcode, _ = unpackUint16(b, 2)
400 + e.Error, _ = unpackUint16(b, 4)
401 + e.Id = uint64(b[6])<<56 | uint64(b[6+1])<<48 | uint64(b[6+2])<<40 |
402 + uint64(b[6+3])<<32 | uint64(b[6+4])<<24 | uint64(b[6+5])<<16 | uint64(b[6+6])<<8 | uint64(b[6+7])
403 + e.LeaseLife = uint32(b[14])<<24 | uint32(b[14+1])<<16 | uint32(b[14+2])<<8 | uint32(b[14+3])
404 + return nil
405 +}
406 +
407 +func (e *EDNS0_LLQ) String() string {
408 + s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
409 + " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
410 + " " + strconv.FormatUint(uint64(e.LeaseLife), 10)
411 + return s
412 +}
413 +
414 +type EDNS0_DAU struct {
415 + Code uint16 // Always EDNS0DAU
416 + AlgCode []uint8
417 +}
418 +
419 +func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU }
420 +func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil }
421 +func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
422 +
423 +func (e *EDNS0_DAU) String() string {
424 + s := ""
425 + for i := 0; i < len(e.AlgCode); i++ {
426 + if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
427 + s += " " + a
428 + } else {
429 + s += " " + strconv.Itoa(int(e.AlgCode[i]))
430 + }
431 + }
432 + return s
433 +}
434 +
435 +type EDNS0_DHU struct {
436 + Code uint16 // Always EDNS0DHU
437 + AlgCode []uint8
438 +}
439 +
440 +func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU }
441 +func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil }
442 +func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
443 +
444 +func (e *EDNS0_DHU) String() string {
445 + s := ""
446 + for i := 0; i < len(e.AlgCode); i++ {
447 + if a, ok := HashToString[e.AlgCode[i]]; ok {
448 + s += " " + a
449 + } else {
450 + s += " " + strconv.Itoa(int(e.AlgCode[i]))
451 + }
452 + }
453 + return s
454 +}
455 +
456 +type EDNS0_N3U struct {
457 + Code uint16 // Always EDNS0N3U
458 + AlgCode []uint8
459 +}
460 +
461 +func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U }
462 +func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil }
463 +func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
464 +
465 +func (e *EDNS0_N3U) String() string {
466 + // Re-use the hash map
467 + s := ""
468 + for i := 0; i < len(e.AlgCode); i++ {
469 + if a, ok := HashToString[e.AlgCode[i]]; ok {
470 + s += " " + a
471 + } else {
472 + s += " " + strconv.Itoa(int(e.AlgCode[i]))
473 + }
474 + }
475 + return s
476 +}
477 +
478 +type EDNS0_EXPIRE struct {
479 + Code uint16 // Always EDNS0EXPIRE
480 + Expire uint32
481 +}
482 +
483 +func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
484 +func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
485 +
486 +func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
487 + b := make([]byte, 4)
488 + b[0] = byte(e.Expire >> 24)
489 + b[1] = byte(e.Expire >> 16)
490 + b[2] = byte(e.Expire >> 8)
491 + b[3] = byte(e.Expire)
492 + return b, nil
493 +}
494 +
495 +func (e *EDNS0_EXPIRE) unpack(b []byte) error {
496 + if len(b) < 4 {
497 + return ErrBuf
498 + }
499 + e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
500 + return nil
501 +}
Godeps/_workspace/src/github.com/miekg/dns/edns_test.go new
+48
@@ -0,0 +1,48 @@
1 +package dns
2 +
3 +import "testing"
4 +
5 +func TestOPTTtl(t *testing.T) {
6 + e := &OPT{}
7 + e.Hdr.Name = "."
8 + e.Hdr.Rrtype = TypeOPT
9 +
10 + if e.Do() {
11 + t.Fail()
12 + }
13 +
14 + e.SetDo()
15 + if !e.Do() {
16 + t.Fail()
17 + }
18 +
19 + oldTtl := e.Hdr.Ttl
20 +
21 + if e.Version() != 0 {
22 + t.Fail()
23 + }
24 +
25 + e.SetVersion(42)
26 + if e.Version() != 42 {
27 + t.Fail()
28 + }
29 +
30 + e.SetVersion(0)
31 + if e.Hdr.Ttl != oldTtl {
32 + t.Fail()
33 + }
34 +
35 + if e.ExtendedRcode() != 0 {
36 + t.Fail()
37 + }
38 +
39 + e.SetExtendedRcode(42)
40 + if e.ExtendedRcode() != 42 {
41 + t.Fail()
42 + }
43 +
44 + e.SetExtendedRcode(0)
45 + if e.Hdr.Ttl != oldTtl {
46 + t.Fail()
47 + }
48 +}
Godeps/_workspace/src/github.com/miekg/dns/example_test.go new
+147
@@ -0,0 +1,147 @@
1 +package dns_test
2 +
3 +import (
4 + "errors"
5 + "fmt"
6 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
7 + "log"
8 + "net"
9 +)
10 +
11 +// Retrieve the MX records for miek.nl.
12 +func ExampleMX() {
13 + config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
14 + c := new(dns.Client)
15 + m := new(dns.Msg)
16 + m.SetQuestion("miek.nl.", dns.TypeMX)
17 + m.RecursionDesired = true
18 + r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
19 + if err != nil {
20 + return
21 + }
22 + if r.Rcode != dns.RcodeSuccess {
23 + return
24 + }
25 + for _, a := range r.Answer {
26 + if mx, ok := a.(*dns.MX); ok {
27 + fmt.Printf("%s\n", mx.String())
28 + }
29 + }
30 +}
31 +
32 +// Retrieve the DNSKEY records of a zone and convert them
33 +// to DS records for SHA1, SHA256 and SHA384.
34 +func ExampleDS(zone string) {
35 + config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
36 + c := new(dns.Client)
37 + m := new(dns.Msg)
38 + if zone == "" {
39 + zone = "miek.nl"
40 + }
41 + m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY)
42 + m.SetEdns0(4096, true)
43 + r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
44 + if err != nil {
45 + return
46 + }
47 + if r.Rcode != dns.RcodeSuccess {
48 + return
49 + }
50 + for _, k := range r.Answer {
51 + if key, ok := k.(*dns.DNSKEY); ok {
52 + for _, alg := range []uint8{dns.SHA1, dns.SHA256, dns.SHA384} {
53 + fmt.Printf("%s; %d\n", key.ToDS(alg).String(), key.Flags)
54 + }
55 + }
56 + }
57 +}
58 +
59 +const TypeAPAIR = 0x0F99
60 +
61 +type APAIR struct {
62 + addr [2]net.IP
63 +}
64 +
65 +func NewAPAIR() dns.PrivateRdata { return new(APAIR) }
66 +
67 +func (rd *APAIR) String() string { return rd.addr[0].String() + " " + rd.addr[1].String() }
68 +func (rd *APAIR) Parse(txt []string) error {
69 + if len(txt) != 2 {
70 + return errors.New("two addresses required for APAIR")
71 + }
72 + for i, s := range txt {
73 + ip := net.ParseIP(s)
74 + if ip == nil {
75 + return errors.New("invalid IP in APAIR text representation")
76 + }
77 + rd.addr[i] = ip
78 + }
79 + return nil
80 +}
81 +
82 +func (rd *APAIR) Pack(buf []byte) (int, error) {
83 + b := append([]byte(rd.addr[0]), []byte(rd.addr[1])...)
84 + n := copy(buf, b)
85 + if n != len(b) {
86 + return n, dns.ErrBuf
87 + }
88 + return n, nil
89 +}
90 +
91 +func (rd *APAIR) Unpack(buf []byte) (int, error) {
92 + ln := net.IPv4len * 2
93 + if len(buf) != ln {
94 + return 0, errors.New("invalid length of APAIR rdata")
95 + }
96 + cp := make([]byte, ln)
97 + copy(cp, buf) // clone bytes to use them in IPs
98 +
99 + rd.addr[0] = net.IP(cp[:3])
100 + rd.addr[1] = net.IP(cp[4:])
101 +
102 + return len(buf), nil
103 +}
104 +
105 +func (rd *APAIR) Copy(dest dns.PrivateRdata) error {
106 + cp := make([]byte, rd.Len())
107 + _, err := rd.Pack(cp)
108 + if err != nil {
109 + return err
110 + }
111 +
112 + d := dest.(*APAIR)
113 + d.addr[0] = net.IP(cp[:3])
114 + d.addr[1] = net.IP(cp[4:])
115 + return nil
116 +}
117 +
118 +func (rd *APAIR) Len() int {
119 + return net.IPv4len * 2
120 +}
121 +
122 +func ExamplePrivateHandle() {
123 + dns.PrivateHandle("APAIR", TypeAPAIR, NewAPAIR)
124 + defer dns.PrivateHandleRemove(TypeAPAIR)
125 +
126 + rr, err := dns.NewRR("miek.nl. APAIR (1.2.3.4 1.2.3.5)")
127 + if err != nil {
128 + log.Fatal("could not parse APAIR record: ", err)
129 + }
130 + fmt.Println(rr)
131 + // Output: miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5
132 +
133 + m := new(dns.Msg)
134 + m.Id = 12345
135 + m.SetQuestion("miek.nl.", TypeAPAIR)
136 + m.Answer = append(m.Answer, rr)
137 +
138 + fmt.Println(m)
139 + // ;; opcode: QUERY, status: NOERROR, id: 12345
140 + // ;; flags: rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
141 + //
142 + // ;; QUESTION SECTION:
143 + // ;miek.nl. IN APAIR
144 + //
145 + // ;; ANSWER SECTION:
146 + // miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5
147 +}
Godeps/_workspace/src/github.com/miekg/dns/format.go new
+96
@@ -0,0 +1,96 @@
1 +package dns
2 +
3 +import (
4 + "net"
5 + "reflect"
6 + "strconv"
7 +)
8 +
9 +// NumField returns the number of rdata fields r has.
10 +func NumField(r RR) int {
11 + return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
12 +}
13 +
14 +// Field returns the rdata field i as a string. Fields are indexed starting from 1.
15 +// RR types that holds slice data, for instance the NSEC type bitmap will return a single
16 +// string where the types are concatenated using a space.
17 +// Accessing non existing fields will cause a panic.
18 +func Field(r RR, i int) string {
19 + if i == 0 {
20 + return ""
21 + }
22 + d := reflect.ValueOf(r).Elem().Field(i)
23 + switch k := d.Kind(); k {
24 + case reflect.String:
25 + return d.String()
26 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
27 + return strconv.FormatInt(d.Int(), 10)
28 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
29 + return strconv.FormatUint(d.Uint(), 10)
30 + case reflect.Slice:
31 + switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
32 + case `dns:"a"`:
33 + // TODO(miek): Hmm store this as 16 bytes
34 + if d.Len() < net.IPv6len {
35 + return net.IPv4(byte(d.Index(0).Uint()),
36 + byte(d.Index(1).Uint()),
37 + byte(d.Index(2).Uint()),
38 + byte(d.Index(3).Uint())).String()
39 + }
40 + return net.IPv4(byte(d.Index(12).Uint()),
41 + byte(d.Index(13).Uint()),
42 + byte(d.Index(14).Uint()),
43 + byte(d.Index(15).Uint())).String()
44 + case `dns:"aaaa"`:
45 + return net.IP{
46 + byte(d.Index(0).Uint()),
47 + byte(d.Index(1).Uint()),
48 + byte(d.Index(2).Uint()),
49 + byte(d.Index(3).Uint()),
50 + byte(d.Index(4).Uint()),
51 + byte(d.Index(5).Uint()),
52 + byte(d.Index(6).Uint()),
53 + byte(d.Index(7).Uint()),
54 + byte(d.Index(8).Uint()),
55 + byte(d.Index(9).Uint()),
56 + byte(d.Index(10).Uint()),
57 + byte(d.Index(11).Uint()),
58 + byte(d.Index(12).Uint()),
59 + byte(d.Index(13).Uint()),
60 + byte(d.Index(14).Uint()),
61 + byte(d.Index(15).Uint()),
62 + }.String()
63 + case `dns:"nsec"`:
64 + if d.Len() == 0 {
65 + return ""
66 + }
67 + s := Type(d.Index(0).Uint()).String()
68 + for i := 1; i < d.Len(); i++ {
69 + s += " " + Type(d.Index(i).Uint()).String()
70 + }
71 + return s
72 + case `dns:"wks"`:
73 + if d.Len() == 0 {
74 + return ""
75 + }
76 + s := strconv.Itoa(int(d.Index(0).Uint()))
77 + for i := 0; i < d.Len(); i++ {
78 + s += " " + strconv.Itoa(int(d.Index(i).Uint()))
79 + }
80 + return s
81 + default:
82 + // if it does not have a tag its a string slice
83 + fallthrough
84 + case `dns:"txt"`:
85 + if d.Len() == 0 {
86 + return ""
87 + }
88 + s := d.Index(0).String()
89 + for i := 1; i < d.Len(); i++ {
90 + s += " " + d.Index(i).String()
91 + }
92 + return s
93 + }
94 + }
95 + return ""
96 +}
Godeps/_workspace/src/github.com/miekg/dns/idn/example_test.go new
+18
@@ -0,0 +1,18 @@
1 +package idn_test
2 +
3 +import (
4 + "fmt"
5 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns/idn"
6 +)
7 +
8 +func ExampleToPunycode() {
9 + name := "インターネット.テスト"
10 + fmt.Printf("%s -> %s", name, idn.ToPunycode(name))
11 + // Output: インターネット.テスト -> xn--eckucmux0ukc.xn--zckzah
12 +}
13 +
14 +func ExampleFromPunycode() {
15 + name := "xn--mgbaja8a1hpac.xn--mgbachtv"
16 + fmt.Printf("%s -> %s", name, idn.FromPunycode(name))
17 + // Output: xn--mgbaja8a1hpac.xn--mgbachtv -> الانترنت.اختبار
18 +}
Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go new
+268
@@ -0,0 +1,268 @@
1 +// Package idn implements encoding from and to punycode as speficied by RFC 3492.
2 +package idn
3 +
4 +import (
5 + "bytes"
6 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
7 + "strings"
8 + "unicode"
9 +)
10 +
11 +// Implementation idea from RFC itself and from from IDNA::Punycode created by
12 +// Tatsuhiko Miyagawa <miyagawa@bulknews.net> and released under Perl Artistic
13 +// License in 2002.
14 +
15 +const (
16 + _MIN rune = 1
17 + _MAX rune = 26
18 + _SKEW rune = 38
19 + _BASE rune = 36
20 + _BIAS rune = 72
21 + _N rune = 128
22 + _DAMP rune = 700
23 +
24 + _DELIMITER = '-'
25 + _PREFIX = "xn--"
26 +)
27 +
28 +// ToPunycode converts unicode domain names to DNS-appropriate punycode names.
29 +// This function would return incorrect result for strings for non-canonical
30 +// unicode strings.
31 +func ToPunycode(s string) string {
32 + tokens := dns.SplitDomainName(s)
33 + switch {
34 + case s == "":
35 + return ""
36 + case tokens == nil: // s == .
37 + return "."
38 + case s[len(s)-1] == '.':
39 + tokens = append(tokens, "")
40 + }
41 +
42 + for i := range tokens {
43 + tokens[i] = string(encode([]byte(tokens[i])))
44 + }
45 + return strings.Join(tokens, ".")
46 +}
47 +
48 +// FromPunycode returns unicode domain name from provided punycode string.
49 +func FromPunycode(s string) string {
50 + tokens := dns.SplitDomainName(s)
51 + switch {
52 + case s == "":
53 + return ""
54 + case tokens == nil: // s == .
55 + return "."
56 + case s[len(s)-1] == '.':
57 + tokens = append(tokens, "")
58 + }
59 + for i := range tokens {
60 + tokens[i] = string(decode([]byte(tokens[i])))
61 + }
62 + return strings.Join(tokens, ".")
63 +}
64 +
65 +// digitval converts single byte into meaningful value that's used to calculate decoded unicode character.
66 +const errdigit = 0xffff
67 +
68 +func digitval(code rune) rune {
69 + switch {
70 + case code >= 'A' && code <= 'Z':
71 + return code - 'A'
72 + case code >= 'a' && code <= 'z':
73 + return code - 'a'
74 + case code >= '0' && code <= '9':
75 + return code - '0' + 26
76 + }
77 + return errdigit
78 +}
79 +
80 +// lettercode finds BASE36 byte (a-z0-9) based on calculated number.
81 +func lettercode(digit rune) rune {
82 + switch {
83 + case digit >= 0 && digit <= 25:
84 + return digit + 'a'
85 + case digit >= 26 && digit <= 36:
86 + return digit - 26 + '0'
87 + }
88 + panic("dns: not reached")
89 +}
90 +
91 +// adapt calculates next bias to be used for next iteration delta.
92 +func adapt(delta rune, numpoints int, firsttime bool) rune {
93 + if firsttime {
94 + delta /= _DAMP
95 + } else {
96 + delta /= 2
97 + }
98 +
99 + var k rune
100 + for delta = delta + delta/rune(numpoints); delta > (_BASE-_MIN)*_MAX/2; k += _BASE {
101 + delta /= _BASE - _MIN
102 + }
103 +
104 + return k + ((_BASE-_MIN+1)*delta)/(delta+_SKEW)
105 +}
106 +
107 +// next finds minimal rune (one with lowest codepoint value) that should be equal or above boundary.
108 +func next(b []rune, boundary rune) rune {
109 + if len(b) == 0 {
110 + panic("dns: invalid set of runes to determine next one")
111 + }
112 + m := b[0]
113 + for _, x := range b[1:] {
114 + if x >= boundary && (m < boundary || x < m) {
115 + m = x
116 + }
117 + }
118 + return m
119 +}
120 +
121 +// preprune converts unicode rune to lower case. At this time it's not
122 +// supporting all things described in RFCs
123 +func preprune(r rune) rune {
124 + if unicode.IsUpper(r) {
125 + r = unicode.ToLower(r)
126 + }
127 + return r
128 +}
129 +
130 +// tfunc is a function that helps calculate each character weight
131 +func tfunc(k, bias rune) rune {
132 + switch {
133 + case k <= bias:
134 + return _MIN
135 + case k >= bias+_MAX:
136 + return _MAX
137 + }
138 + return k - bias
139 +}
140 +
141 +// encode transforms Unicode input bytes (that represent DNS label) into punycode bytestream
142 +func encode(input []byte) []byte {
143 + n, bias := _N, _BIAS
144 +
145 + b := bytes.Runes(input)
146 + for i := range b {
147 + b[i] = preprune(b[i])
148 + }
149 +
150 + basic := make([]byte, 0, len(b))
151 + for _, ltr := range b {
152 + if ltr <= 0x7f {
153 + basic = append(basic, byte(ltr))
154 + }
155 + }
156 + basiclen := len(basic)
157 + fulllen := len(b)
158 + if basiclen == fulllen {
159 + return basic
160 + }
161 +
162 + var out bytes.Buffer
163 +
164 + out.WriteString(_PREFIX)
165 + if basiclen > 0 {
166 + out.Write(basic)
167 + out.WriteByte(_DELIMITER)
168 + }
169 +
170 + var (
171 + ltr, nextltr rune
172 + delta, q rune // delta calculation (see rfc)
173 + t, k, cp rune // weight and codepoint calculation
174 + )
175 +
176 + s := &bytes.Buffer{}
177 + for h := basiclen; h < fulllen; n, delta = n+1, delta+1 {
178 + nextltr = next(b, n)
179 + s.Truncate(0)
180 + s.WriteRune(nextltr)
181 + delta, n = delta+(nextltr-n)*rune(h+1), nextltr
182 +
183 + for _, ltr = range b {
184 + if ltr < n {
185 + delta++
186 + }
187 + if ltr == n {
188 + q = delta
189 + for k = _BASE; ; k += _BASE {
190 + t = tfunc(k, bias)
191 + if q < t {
192 + break
193 + }
194 + cp = t + ((q - t) % (_BASE - t))
195 + out.WriteRune(lettercode(cp))
196 + q = (q - t) / (_BASE - t)
197 + }
198 +
199 + out.WriteRune(lettercode(q))
200 +
201 + bias = adapt(delta, h+1, h == basiclen)
202 + h, delta = h+1, 0
203 + }
204 + }
205 + }
206 + return out.Bytes()
207 +}
208 +
209 +// decode transforms punycode input bytes (that represent DNS label) into Unicode bytestream
210 +func decode(b []byte) []byte {
211 + src := b // b would move and we need to keep it
212 +
213 + n, bias := _N, _BIAS
214 + if !bytes.HasPrefix(b, []byte(_PREFIX)) {
215 + return b
216 + }
217 + out := make([]rune, 0, len(b))
218 + b = b[len(_PREFIX):]
219 + for pos, x := range b {
220 + if x == _DELIMITER {
221 + out = append(out, bytes.Runes(b[:pos])...)
222 + b = b[pos+1:] // trim source string
223 + break
224 + }
225 + }
226 + if len(b) == 0 {
227 + return src
228 + }
229 + var (
230 + i, oldi, w rune
231 + ch byte
232 + t, digit rune
233 + ln int
234 + )
235 +
236 + for i = 0; len(b) > 0; i++ {
237 + oldi, w = i, 1
238 + for k := _BASE; len(b) > 0; k += _BASE {
239 + ch, b = b[0], b[1:]
240 + digit = digitval(rune(ch))
241 + if digit == errdigit {
242 + return src
243 + }
244 + i += digit * w
245 +
246 + t = tfunc(k, bias)
247 + if digit < t {
248 + break
249 + }
250 +
251 + w *= _BASE - t
252 + }
253 + ln = len(out) + 1
254 + bias = adapt(i-oldi, ln, oldi == 0)
255 + n += i / rune(ln)
256 + i = i % rune(ln)
257 + // insert
258 + out = append(out, 0)
259 + copy(out[i+1:], out[i:])
260 + out[i] = n
261 + }
262 +
263 + var ret bytes.Buffer
264 + for _, r := range out {
265 + ret.WriteRune(r)
266 + }
267 + return ret.Bytes()
268 +}
Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go new
+94
@@ -0,0 +1,94 @@
1 +package idn
2 +
3 +import (
4 + "strings"
5 + "testing"
6 +)
7 +
8 +var testcases = [][2]string{
9 + {"", ""},
10 + {"a", "a"},
11 + {"A-B", "a-b"},
12 + {"AbC", "abc"},
13 + {"я", "xn--41a"},
14 + {"zя", "xn--z-0ub"},
15 + {"ЯZ", "xn--z-zub"},
16 + {"إختبار", "xn--kgbechtv"},
17 + {"آزمایشی", "xn--hgbk6aj7f53bba"},
18 + {"测试", "xn--0zwm56d"},
19 + {"測試", "xn--g6w251d"},
20 + {"Испытание", "xn--80akhbyknj4f"},
21 + {"परीक्षा", "xn--11b5bs3a9aj6g"},
22 + {"δοκιμή", "xn--jxalpdlp"},
23 + {"테스트", "xn--9t4b11yi5a"},
24 + {"טעסט", "xn--deba0ad"},
25 + {"テスト", "xn--zckzah"},
26 + {"பரிட்சை", "xn--hlcj6aya9esc7a"},
27 +}
28 +
29 +func TestEncodeDecodePunycode(t *testing.T) {
30 + for _, tst := range testcases {
31 + enc := encode([]byte(tst[0]))
32 + if string(enc) != tst[1] {
33 + t.Errorf("%s encodeded as %s but should be %s", tst[0], enc, tst[1])
34 + }
35 + dec := decode([]byte(tst[1]))
36 + if string(dec) != strings.ToLower(tst[0]) {
37 + t.Errorf("%s decoded as %s but should be %s", tst[1], dec, strings.ToLower(tst[0]))
38 + }
39 + }
40 +}
41 +
42 +func TestToFromPunycode(t *testing.T) {
43 + for _, tst := range testcases {
44 + // assert unicode.com == punycode.com
45 + full := ToPunycode(tst[0] + ".com")
46 + if full != tst[1]+".com" {
47 + t.Errorf("invalid result from string conversion to punycode, %s and should be %s.com", full, tst[1])
48 + }
49 + // assert punycode.punycode == unicode.unicode
50 + decoded := FromPunycode(tst[1] + "." + tst[1])
51 + if decoded != strings.ToLower(tst[0]+"."+tst[0]) {
52 + t.Errorf("invalid result from string conversion to punycode, %s and should be %s.%s", decoded, tst[0], tst[0])
53 + }
54 + }
55 +}
56 +
57 +func TestEncodeDecodeFinalPeriod(t *testing.T) {
58 + for _, tst := range testcases {
59 + // assert unicode.com. == punycode.com.
60 + full := ToPunycode(tst[0] + ".")
61 + if full != tst[1]+"." {
62 + t.Errorf("invalid result from string conversion to punycode when period added at the end, %#v and should be %#v", full, tst[1]+".")
63 + }
64 + // assert punycode.com. == unicode.com.
65 + decoded := FromPunycode(tst[1] + ".")
66 + if decoded != strings.ToLower(tst[0]+".") {
67 + t.Errorf("invalid result from string conversion to punycode when period added, %#v and should be %#v", decoded, tst[0]+".")
68 + }
69 + full = ToPunycode(tst[0])
70 + if full != tst[1] {
71 + t.Errorf("invalid result from string conversion to punycode when no period added at the end, %#v and should be %#v", full, tst[1]+".")
72 + }
73 + // assert punycode.com. == unicode.com.
74 + decoded = FromPunycode(tst[1])
75 + if decoded != strings.ToLower(tst[0]) {
76 + t.Errorf("invalid result from string conversion to punycode when no period added, %#v and should be %#v", decoded, tst[0]+".")
77 + }
78 + }
79 +}
80 +
81 +var invalid = []string{
82 + "xn--*",
83 + "xn--",
84 + "xn---",
85 +}
86 +
87 +func TestInvalidPunycode(t *testing.T) {
88 + for _, d := range invalid {
89 + s := FromPunycode(d)
90 + if s != d {
91 + t.Errorf("Changed invalid name %s to %#v", d, s)
92 + }
93 + }
94 +}
Godeps/_workspace/src/github.com/miekg/dns/labels.go new
+162
@@ -0,0 +1,162 @@
1 +package dns
2 +
3 +// Holds a bunch of helper functions for dealing with labels.
4 +
5 +// SplitDomainName splits a name string into it's labels.
6 +// www.miek.nl. returns []string{"www", "miek", "nl"}
7 +// The root label (.) returns nil. Note that using
8 +// strings.Split(s) will work in most cases, but does not handle
9 +// escaped dots (\.) for instance.
10 +func SplitDomainName(s string) (labels []string) {
11 + if len(s) == 0 {
12 + return nil
13 + }
14 + fqdnEnd := 0 // offset of the final '.' or the length of the name
15 + idx := Split(s)
16 + begin := 0
17 + if s[len(s)-1] == '.' {
18 + fqdnEnd = len(s) - 1
19 + } else {
20 + fqdnEnd = len(s)
21 + }
22 +
23 + switch len(idx) {
24 + case 0:
25 + return nil
26 + case 1:
27 + // no-op
28 + default:
29 + end := 0
30 + for i := 1; i < len(idx); i++ {
31 + end = idx[i]
32 + labels = append(labels, s[begin:end-1])
33 + begin = end
34 + }
35 + }
36 +
37 + labels = append(labels, s[begin:fqdnEnd])
38 + return labels
39 +}
40 +
41 +// CompareDomainName compares the names s1 and s2 and
42 +// returns how many labels they have in common starting from the *right*.
43 +// The comparison stops at the first inequality. The names are not downcased
44 +// before the comparison.
45 +//
46 +// www.miek.nl. and miek.nl. have two labels in common: miek and nl
47 +// www.miek.nl. and www.bla.nl. have one label in common: nl
48 +func CompareDomainName(s1, s2 string) (n int) {
49 + s1 = Fqdn(s1)
50 + s2 = Fqdn(s2)
51 + l1 := Split(s1)
52 + l2 := Split(s2)
53 +
54 + // the first check: root label
55 + if l1 == nil || l2 == nil {
56 + return
57 + }
58 +
59 + j1 := len(l1) - 1 // end
60 + i1 := len(l1) - 2 // start
61 + j2 := len(l2) - 1
62 + i2 := len(l2) - 2
63 + // the second check can be done here: last/only label
64 + // before we fall through into the for-loop below
65 + if s1[l1[j1]:] == s2[l2[j2]:] {
66 + n++
67 + } else {
68 + return
69 + }
70 + for {
71 + if i1 < 0 || i2 < 0 {
72 + break
73 + }
74 + if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
75 + n++
76 + } else {
77 + break
78 + }
79 + j1--
80 + i1--
81 + j2--
82 + i2--
83 + }
84 + return
85 +}
86 +
87 +// CountLabel counts the the number of labels in the string s.
88 +func CountLabel(s string) (labels int) {
89 + if s == "." {
90 + return
91 + }
92 + off := 0
93 + end := false
94 + for {
95 + off, end = NextLabel(s, off)
96 + labels++
97 + if end {
98 + return
99 + }
100 + }
101 + panic("dns: not reached")
102 +}
103 +
104 +// Split splits a name s into its label indexes.
105 +// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
106 +// The root name (.) returns nil. Also see dns.SplitDomainName.
107 +func Split(s string) []int {
108 + if s == "." {
109 + return nil
110 + }
111 + idx := make([]int, 1, 3)
112 + off := 0
113 + end := false
114 +
115 + for {
116 + off, end = NextLabel(s, off)
117 + if end {
118 + return idx
119 + }
120 + idx = append(idx, off)
121 + }
122 + panic("dns: not reached")
123 +}
124 +
125 +// NextLabel returns the index of the start of the next label in the
126 +// string s starting at offset.
127 +// The bool end is true when the end of the string has been reached.
128 +func NextLabel(s string, offset int) (i int, end bool) {
129 + quote := false
130 + for i = offset; i < len(s)-1; i++ {
131 + switch s[i] {
132 + case '\\':
133 + quote = !quote
134 + default:
135 + quote = false
136 + case '.':
137 + if quote {
138 + quote = !quote
139 + continue
140 + }
141 + return i + 1, false
142 + }
143 + }
144 + return i + 1, true
145 +}
146 +
147 +// PrevLabel returns the index of the label when starting from the right and
148 +// jumping n labels to the left.
149 +// The bool start is true when the start of the string has been overshot.
150 +func PrevLabel(s string, n int) (i int, start bool) {
151 + if n == 0 {
152 + return len(s), false
153 + }
154 + lab := Split(s)
155 + if lab == nil {
156 + return 0, true
157 + }
158 + if n > len(lab) {
159 + return 0, true
160 + }
161 + return lab[len(lab)-n], false
162 +}
Godeps/_workspace/src/github.com/miekg/dns/labels_test.go new
+214
@@ -0,0 +1,214 @@
1 +package dns
2 +
3 +import (
4 + "testing"
5 +)
6 +
7 +func TestCompareDomainName(t *testing.T) {
8 + s1 := "www.miek.nl."
9 + s2 := "miek.nl."
10 + s3 := "www.bla.nl."
11 + s4 := "nl.www.bla."
12 + s5 := "nl"
13 + s6 := "miek.nl"
14 +
15 + if CompareDomainName(s1, s2) != 2 {
16 + t.Logf("%s with %s should be %d", s1, s2, 2)
17 + t.Fail()
18 + }
19 + if CompareDomainName(s1, s3) != 1 {
20 + t.Logf("%s with %s should be %d", s1, s3, 1)
21 + t.Fail()
22 + }
23 + if CompareDomainName(s3, s4) != 0 {
24 + t.Logf("%s with %s should be %d", s3, s4, 0)
25 + t.Fail()
26 + }
27 + // Non qualified tests
28 + if CompareDomainName(s1, s5) != 1 {
29 + t.Logf("%s with %s should be %d", s1, s5, 1)
30 + t.Fail()
31 + }
32 + if CompareDomainName(s1, s6) != 2 {
33 + t.Logf("%s with %s should be %d", s1, s5, 2)
34 + t.Fail()
35 + }
36 +
37 + if CompareDomainName(s1, ".") != 0 {
38 + t.Logf("%s with %s should be %d", s1, s5, 0)
39 + t.Fail()
40 + }
41 + if CompareDomainName(".", ".") != 0 {
42 + t.Logf("%s with %s should be %d", ".", ".", 0)
43 + t.Fail()
44 + }
45 +}
46 +
47 +func TestSplit(t *testing.T) {
48 + splitter := map[string]int{
49 + "www.miek.nl.": 3,
50 + "www.miek.nl": 3,
51 + "www..miek.nl": 4,
52 + `www\.miek.nl.`: 2,
53 + `www\\.miek.nl.`: 3,
54 + ".": 0,
55 + "nl.": 1,
56 + "nl": 1,
57 + "com.": 1,
58 + ".com.": 2,
59 + }
60 + for s, i := range splitter {
61 + if x := len(Split(s)); x != i {
62 + t.Logf("labels should be %d, got %d: %s %v\n", i, x, s, Split(s))
63 + t.Fail()
64 + } else {
65 + t.Logf("%s %v\n", s, Split(s))
66 + }
67 + }
68 +}
69 +
70 +func TestSplit2(t *testing.T) {
71 + splitter := map[string][]int{
72 + "www.miek.nl.": []int{0, 4, 9},
73 + "www.miek.nl": []int{0, 4, 9},
74 + "nl": []int{0},
75 + }
76 + for s, i := range splitter {
77 + x := Split(s)
78 + switch len(i) {
79 + case 1:
80 + if x[0] != i[0] {
81 + t.Logf("labels should be %v, got %v: %s\n", i, x, s)
82 + t.Fail()
83 + }
84 + default:
85 + if x[0] != i[0] || x[1] != i[1] || x[2] != i[2] {
86 + t.Logf("labels should be %v, got %v: %s\n", i, x, s)
87 + t.Fail()
88 + }
89 + }
90 + }
91 +}
92 +
93 +func TestPrevLabel(t *testing.T) {
94 + type prev struct {
95 + string
96 + int
97 + }
98 + prever := map[prev]int{
99 + prev{"www.miek.nl.", 0}: 12,
100 + prev{"www.miek.nl.", 1}: 9,
101 + prev{"www.miek.nl.", 2}: 4,
102 +
103 + prev{"www.miek.nl", 0}: 11,
104 + prev{"www.miek.nl", 1}: 9,
105 + prev{"www.miek.nl", 2}: 4,
106 +
107 + prev{"www.miek.nl.", 5}: 0,
108 + prev{"www.miek.nl", 5}: 0,
109 +
110 + prev{"www.miek.nl.", 3}: 0,
111 + prev{"www.miek.nl", 3}: 0,
112 + }
113 + for s, i := range prever {
114 + x, ok := PrevLabel(s.string, s.int)
115 + if i != x {
116 + t.Logf("label should be %d, got %d, %t: preving %d, %s\n", i, x, ok, s.int, s.string)
117 + t.Fail()
118 + }
119 + }
120 +}
121 +
122 +func TestCountLabel(t *testing.T) {
123 + splitter := map[string]int{
124 + "www.miek.nl.": 3,
125 + "www.miek.nl": 3,
126 + "nl": 1,
127 + ".": 0,
128 + }
129 + for s, i := range splitter {
130 + x := CountLabel(s)
131 + if x != i {
132 + t.Logf("CountLabel should have %d, got %d\n", i, x)
133 + t.Fail()
134 + }
135 + }
136 +}
137 +
138 +func TestSplitDomainName(t *testing.T) {
139 + labels := map[string][]string{
140 + "miek.nl": []string{"miek", "nl"},
141 + ".": nil,
142 + "www.miek.nl.": []string{"www", "miek", "nl"},
143 + "www.miek.nl": []string{"www", "miek", "nl"},
144 + "www..miek.nl": []string{"www", "", "miek", "nl"},
145 + `www\.miek.nl`: []string{`www\.miek`, "nl"},
146 + `www\\.miek.nl`: []string{`www\\`, "miek", "nl"},
147 + }
148 +domainLoop:
149 + for domain, splits := range labels {
150 + parts := SplitDomainName(domain)
151 + if len(parts) != len(splits) {
152 + t.Logf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
153 + t.Fail()
154 + continue domainLoop
155 + }
156 + for i := range parts {
157 + if parts[i] != splits[i] {
158 + t.Logf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
159 + t.Fail()
160 + continue domainLoop
161 + }
162 + }
163 + }
164 +}
165 +
166 +func TestIsDomainName(t *testing.T) {
167 + type ret struct {
168 + ok bool
169 + lab int
170 + }
171 + names := map[string]*ret{
172 + "..": &ret{false, 1},
173 + "@.": &ret{true, 1},
174 + "www.example.com": &ret{true, 3},
175 + "www.e%ample.com": &ret{true, 3},
176 + "www.example.com.": &ret{true, 3},
177 + "mi\\k.nl.": &ret{true, 2},
178 + "mi\\k.nl": &ret{true, 2},
179 + }
180 + for d, ok := range names {
181 + l, k := IsDomainName(d)
182 + if ok.ok != k || ok.lab != l {
183 + t.Logf(" got %v %d for %s ", k, l, d)
184 + t.Logf("have %v %d for %s ", ok.ok, ok.lab, d)
185 + t.Fail()
186 + }
187 + }
188 +}
189 +
190 +func BenchmarkSplitLabels(b *testing.B) {
191 + for i := 0; i < b.N; i++ {
192 + Split("www.example.com")
193 + }
194 +}
195 +
196 +func BenchmarkLenLabels(b *testing.B) {
197 + for i := 0; i < b.N; i++ {
198 + CountLabel("www.example.com")
199 + }
200 +}
201 +
202 +func BenchmarkCompareLabels(b *testing.B) {
203 + for i := 0; i < b.N; i++ {
204 + CompareDomainName("www.example.com", "aa.example.com")
205 + }
206 +}
207 +
208 +func BenchmarkIsSubDomain(b *testing.B) {
209 + for i := 0; i < b.N; i++ {
210 + IsSubDomain("www.example.com", "aa.example.com")
211 + IsSubDomain("example.com", "aa.example.com")
212 + IsSubDomain("miek.nl", "aa.example.com")
213 + }
214 +}
Godeps/_workspace/src/github.com/miekg/dns/msg.go new
+1937
@@ -0,0 +1,1937 @@
1 +// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
2 +// and to - Pack() - wire format.
3 +// All the packers and unpackers take a (msg []byte, off int)
4 +// and return (off1 int, ok bool). If they return ok==false, they
5 +// also return off1==len(msg), so that the next unpacker will
6 +// also fail. This lets us avoid checks of ok until the end of a
7 +// packing sequence.
8 +
9 +package dns
10 +
11 +import (
12 + "encoding/base32"
13 + "encoding/base64"
14 + "encoding/hex"
15 + "math/big"
16 + "math/rand"
17 + "net"
18 + "reflect"
19 + "strconv"
20 + "time"
21 +)
22 +
23 +const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
24 +
25 +var (
26 + ErrAlg error = &Error{err: "bad algorithm"}
27 + ErrAuth error = &Error{err: "bad authentication"}
28 + ErrBuf error = &Error{err: "buffer size too small"}
29 + ErrConnEmpty error = &Error{err: "conn has no connection"}
30 + ErrConn error = &Error{err: "conn holds both UDP and TCP connection"}
31 + ErrExtendedRcode error = &Error{err: "bad extended rcode"}
32 + ErrFqdn error = &Error{err: "domain must be fully qualified"}
33 + ErrId error = &Error{err: "id mismatch"}
34 + ErrKeyAlg error = &Error{err: "bad key algorithm"}
35 + ErrKey error = &Error{err: "bad key"}
36 + ErrKeySize error = &Error{err: "bad key size"}
37 + ErrNoSig error = &Error{err: "no signature found"}
38 + ErrPrivKey error = &Error{err: "bad private key"}
39 + ErrRcode error = &Error{err: "bad rcode"}
40 + ErrRdata error = &Error{err: "bad rdata"}
41 + ErrRRset error = &Error{err: "bad rrset"}
42 + ErrSecret error = &Error{err: "no secrets defined"}
43 + ErrServ error = &Error{err: "no servers could be reached"}
44 + ErrShortRead error = &Error{err: "short read"}
45 + ErrSig error = &Error{err: "bad signature"}
46 + ErrSigGen error = &Error{err: "bad signature generation"}
47 + ErrSoa error = &Error{err: "no SOA"}
48 + ErrTime error = &Error{err: "bad time"}
49 +)
50 +
51 +// Id, by default, returns a 16 bits random number to be used as a
52 +// message id. The random provided should be good enough. This being a
53 +// variable the function can be reassigned to a custom function.
54 +// For instance, to make it return a static value:
55 +//
56 +// dns.Id = func() uint16 { return 3 }
57 +var Id func() uint16 = id
58 +
59 +// A manually-unpacked version of (id, bits).
60 +// This is in its own struct for easy printing.
61 +type MsgHdr struct {
62 + Id uint16
63 + Response bool
64 + Opcode int
65 + Authoritative bool
66 + Truncated bool
67 + RecursionDesired bool
68 + RecursionAvailable bool
69 + Zero bool
70 + AuthenticatedData bool
71 + CheckingDisabled bool
72 + Rcode int
73 +}
74 +
75 +// The layout of a DNS message.
76 +type Msg struct {
77 + MsgHdr
78 + Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format. This not part of the official DNS packet format.
79 + Question []Question // Holds the RR(s) of the question section.
80 + Answer []RR // Holds the RR(s) of the answer section.
81 + Ns []RR // Holds the RR(s) of the authority section.
82 + Extra []RR // Holds the RR(s) of the additional section.
83 +}
84 +
85 +// Map of strings for each RR wire type.
86 +var TypeToString = map[uint16]string{
87 + TypeA: "A",
88 + TypeAAAA: "AAAA",
89 + TypeAFSDB: "AFSDB",
90 + TypeANY: "ANY", // Meta RR
91 + TypeATMA: "ATMA",
92 + TypeAXFR: "AXFR", // Meta RR
93 + TypeCAA: "CAA",
94 + TypeCDNSKEY: "CDNSKEY",
95 + TypeCDS: "CDS",
96 + TypeCERT: "CERT",
97 + TypeCNAME: "CNAME",
98 + TypeDHCID: "DHCID",
99 + TypeDLV: "DLV",
100 + TypeDNAME: "DNAME",
101 + TypeDNSKEY: "DNSKEY",
102 + TypeDS: "DS",
103 + TypeEID: "EID",
104 + TypeEUI48: "EUI48",
105 + TypeEUI64: "EUI64",
106 + TypeGID: "GID",
107 + TypeGPOS: "GPOS",
108 + TypeHINFO: "HINFO",
109 + TypeHIP: "HIP",
110 + TypeIPSECKEY: "IPSECKEY",
111 + TypeISDN: "ISDN",
112 + TypeIXFR: "IXFR", // Meta RR
113 + TypeKEY: "KEY",
114 + TypeKX: "KX",
115 + TypeL32: "L32",
116 + TypeL64: "L64",
117 + TypeLOC: "LOC",
118 + TypeLP: "LP",
119 + TypeMB: "MB",
120 + TypeMD: "MD",
121 + TypeMF: "MF",
122 + TypeMG: "MG",
123 + TypeMINFO: "MINFO",
124 + TypeMR: "MR",
125 + TypeMX: "MX",
126 + TypeNAPTR: "NAPTR",
127 + TypeNID: "NID",
128 + TypeNINFO: "NINFO",
129 + TypeNIMLOC: "NIMLOC",
130 + TypeNS: "NS",
131 + TypeNSAP: "NSAP",
132 + TypeNSAPPTR: "NSAP-PTR",
133 + TypeNSEC3: "NSEC3",
134 + TypeNSEC3PARAM: "NSEC3PARAM",
135 + TypeNSEC: "NSEC",
136 + TypeNULL: "NULL",
137 + TypeOPT: "OPT",
138 + TypeOPENPGPKEY: "OPENPGPKEY",
139 + TypePTR: "PTR",
140 + TypeRKEY: "RKEY",
141 + TypeRP: "RP",
142 + TypeRRSIG: "RRSIG",
143 + TypeRT: "RT",
144 + TypeSIG: "SIG",
145 + TypeSOA: "SOA",
146 + TypeSPF: "SPF",
147 + TypeSRV: "SRV",
148 + TypeSSHFP: "SSHFP",
149 + TypeTA: "TA",
150 + TypeTALINK: "TALINK",
151 + TypeTKEY: "TKEY", // Meta RR
152 + TypeTLSA: "TLSA",
153 + TypeTSIG: "TSIG", // Meta RR
154 + TypeTXT: "TXT",
155 + TypePX: "PX",
156 + TypeUID: "UID",
157 + TypeUINFO: "UINFO",
158 + TypeUNSPEC: "UNSPEC",
159 + TypeURI: "URI",
160 + TypeWKS: "WKS",
161 + TypeX25: "X25",
162 +}
163 +
164 +// Reverse, needed for string parsing.
165 +var StringToType = reverseInt16(TypeToString)
166 +var StringToClass = reverseInt16(ClassToString)
167 +
168 +// Map of opcodes strings.
169 +var StringToOpcode = reverseInt(OpcodeToString)
170 +
171 +// Map of rcodes strings.
172 +var StringToRcode = reverseInt(RcodeToString)
173 +
174 +// Map of strings for each CLASS wire type.
175 +var ClassToString = map[uint16]string{
176 + ClassINET: "IN",
177 + ClassCSNET: "CS",
178 + ClassCHAOS: "CH",
179 + ClassHESIOD: "HS",
180 + ClassNONE: "NONE",
181 + ClassANY: "ANY",
182 +}
183 +
184 +// Map of strings for opcodes.
185 +var OpcodeToString = map[int]string{
186 + OpcodeQuery: "QUERY",
187 + OpcodeIQuery: "IQUERY",
188 + OpcodeStatus: "STATUS",
189 + OpcodeNotify: "NOTIFY",
190 + OpcodeUpdate: "UPDATE",
191 +}
192 +
193 +// Map of strings for rcodes.
194 +var RcodeToString = map[int]string{
195 + RcodeSuccess: "NOERROR",
196 + RcodeFormatError: "FORMERR",
197 + RcodeServerFailure: "SERVFAIL",
198 + RcodeNameError: "NXDOMAIN",
199 + RcodeNotImplemented: "NOTIMPL",
200 + RcodeRefused: "REFUSED",
201 + RcodeYXDomain: "YXDOMAIN", // From RFC 2136
202 + RcodeYXRrset: "YXRRSET",
203 + RcodeNXRrset: "NXRRSET",
204 + RcodeNotAuth: "NOTAUTH",
205 + RcodeNotZone: "NOTZONE",
206 + RcodeBadSig: "BADSIG", // Also known as RcodeBadVers, see RFC 6891
207 + // RcodeBadVers: "BADVERS",
208 + RcodeBadKey: "BADKEY",
209 + RcodeBadTime: "BADTIME",
210 + RcodeBadMode: "BADMODE",
211 + RcodeBadName: "BADNAME",
212 + RcodeBadAlg: "BADALG",
213 + RcodeBadTrunc: "BADTRUNC",
214 +}
215 +
216 +// Rather than write the usual handful of routines to pack and
217 +// unpack every message that can appear on the wire, we use
218 +// reflection to write a generic pack/unpack for structs and then
219 +// use it. Thus, if in the future we need to define new message
220 +// structs, no new pack/unpack/printing code needs to be written.
221 +
222 +// Domain names are a sequence of counted strings
223 +// split at the dots. They end with a zero-length string.
224 +
225 +// PackDomainName packs a domain name s into msg[off:].
226 +// If compression is wanted compress must be true and the compression
227 +// map needs to hold a mapping between domain names and offsets
228 +// pointing into msg[].
229 +func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
230 + off1, _, err = packDomainName(s, msg, off, compression, compress)
231 + return
232 +}
233 +
234 +func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) {
235 + // special case if msg == nil
236 + lenmsg := 256
237 + if msg != nil {
238 + lenmsg = len(msg)
239 + }
240 + ls := len(s)
241 + if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
242 + return off, 0, nil
243 + }
244 + // If not fully qualified, error out, but only if msg == nil #ugly
245 + switch {
246 + case msg == nil:
247 + if s[ls-1] != '.' {
248 + s += "."
249 + ls++
250 + }
251 + case msg != nil:
252 + if s[ls-1] != '.' {
253 + return lenmsg, 0, ErrFqdn
254 + }
255 + }
256 + // Each dot ends a segment of the name.
257 + // We trade each dot byte for a length byte.
258 + // Except for escaped dots (\.), which are normal dots.
259 + // There is also a trailing zero.
260 +
261 + // Compression
262 + nameoffset := -1
263 + pointer := -1
264 + // Emit sequence of counted strings, chopping at dots.
265 + begin := 0
266 + bs := []byte(s)
267 + ro_bs, bs_fresh, escaped_dot := s, true, false
268 + for i := 0; i < ls; i++ {
269 + if bs[i] == '\\' {
270 + for j := i; j < ls-1; j++ {
271 + bs[j] = bs[j+1]
272 + }
273 + ls--
274 + if off+1 > lenmsg {
275 + return lenmsg, labels, ErrBuf
276 + }
277 + // check for \DDD
278 + if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
279 + bs[i] = dddToByte(bs[i:])
280 + for j := i + 1; j < ls-2; j++ {
281 + bs[j] = bs[j+2]
282 + }
283 + ls -= 2
284 + } else if bs[i] == 't' {
285 + bs[i] = '\t'
286 + } else if bs[i] == 'r' {
287 + bs[i] = '\r'
288 + } else if bs[i] == 'n' {
289 + bs[i] = '\n'
290 + }
291 + escaped_dot = bs[i] == '.'
292 + bs_fresh = false
293 + continue
294 + }
295 +
296 + if bs[i] == '.' {
297 + if i > 0 && bs[i-1] == '.' && !escaped_dot {
298 + // two dots back to back is not legal
299 + return lenmsg, labels, ErrRdata
300 + }
301 + if i-begin >= 1<<6 { // top two bits of length must be clear
302 + return lenmsg, labels, ErrRdata
303 + }
304 + // off can already (we're in a loop) be bigger than len(msg)
305 + // this happens when a name isn't fully qualified
306 + if off+1 > lenmsg {
307 + return lenmsg, labels, ErrBuf
308 + }
309 + if msg != nil {
310 + msg[off] = byte(i - begin)
311 + }
312 + offset := off
313 + off++
314 + for j := begin; j < i; j++ {
315 + if off+1 > lenmsg {
316 + return lenmsg, labels, ErrBuf
317 + }
318 + if msg != nil {
319 + msg[off] = bs[j]
320 + }
321 + off++
322 + }
323 + if compress && !bs_fresh {
324 + ro_bs = string(bs)
325 + bs_fresh = true
326 + }
327 + // Dont try to compress '.'
328 + if compress && ro_bs[begin:] != "." {
329 + if p, ok := compression[ro_bs[begin:]]; !ok {
330 + // Only offsets smaller than this can be used.
331 + if offset < maxCompressionOffset {
332 + compression[ro_bs[begin:]] = offset
333 + }
334 + } else {
335 + // The first hit is the longest matching dname
336 + // keep the pointer offset we get back and store
337 + // the offset of the current name, because that's
338 + // where we need to insert the pointer later
339 +
340 + // If compress is true, we're allowed to compress this dname
341 + if pointer == -1 && compress {
342 + pointer = p // Where to point to
343 + nameoffset = offset // Where to point from
344 + break
345 + }
346 + }
347 + }
348 + labels++
349 + begin = i + 1
350 + }
351 + escaped_dot = false
352 + }
353 + // Root label is special
354 + if len(bs) == 1 && bs[0] == '.' {
355 + return off, labels, nil
356 + }
357 + // If we did compression and we find something add the pointer here
358 + if pointer != -1 {
359 + // We have two bytes (14 bits) to put the pointer in
360 + // if msg == nil, we will never do compression
361 + msg[nameoffset], msg[nameoffset+1] = packUint16(uint16(pointer ^ 0xC000))
362 + off = nameoffset + 1
363 + goto End
364 + }
365 + if msg != nil {
366 + msg[off] = 0
367 + }
368 +End:
369 + off++
370 + return off, labels, nil
371 +}
372 +
373 +// Unpack a domain name.
374 +// In addition to the simple sequences of counted strings above,
375 +// domain names are allowed to refer to strings elsewhere in the
376 +// packet, to avoid repeating common suffixes when returning
377 +// many entries in a single domain. The pointers are marked
378 +// by a length byte with the top two bits set. Ignoring those
379 +// two bits, that byte and the next give a 14 bit offset from msg[0]
380 +// where we should pick up the trail.
381 +// Note that if we jump elsewhere in the packet,
382 +// we return off1 == the offset after the first pointer we found,
383 +// which is where the next record will start.
384 +// In theory, the pointers are only allowed to jump backward.
385 +// We let them jump anywhere and stop jumping after a while.
386 +
387 +// UnpackDomainName unpacks a domain name into a string.
388 +func UnpackDomainName(msg []byte, off int) (string, int, error) {
389 + s := make([]byte, 0, 64)
390 + off1 := 0
391 + lenmsg := len(msg)
392 + ptr := 0 // number of pointers followed
393 +Loop:
394 + for {
395 + if off >= lenmsg {
396 + return "", lenmsg, ErrBuf
397 + }
398 + c := int(msg[off])
399 + off++
400 + switch c & 0xC0 {
401 + case 0x00:
402 + if c == 0x00 {
403 + // end of name
404 + if len(s) == 0 {
405 + return ".", off, nil
406 + }
407 + break Loop
408 + }
409 + // literal string
410 + if off+c > lenmsg {
411 + return "", lenmsg, ErrBuf
412 + }
413 + for j := off; j < off+c; j++ {
414 + switch b := msg[j]; b {
415 + case '.', '(', ')', ';', ' ', '@':
416 + fallthrough
417 + case '"', '\\':
418 + s = append(s, '\\', b)
419 + case '\t':
420 + s = append(s, '\\', 't')
421 + case '\r':
422 + s = append(s, '\\', 'r')
423 + default:
424 + if b < 32 || b >= 127 { // unprintable use \DDD
425 + var buf [3]byte
426 + bufs := strconv.AppendInt(buf[:0], int64(b), 10)
427 + s = append(s, '\\')
428 + for i := 0; i < 3-len(bufs); i++ {
429 + s = append(s, '0')
430 + }
431 + for _, r := range bufs {
432 + s = append(s, r)
433 + }
434 + } else {
435 + s = append(s, b)
436 + }
437 + }
438 + }
439 + s = append(s, '.')
440 + off += c
441 + case 0xC0:
442 + // pointer to somewhere else in msg.
443 + // remember location after first ptr,
444 + // since that's how many bytes we consumed.
445 + // also, don't follow too many pointers --
446 + // maybe there's a loop.
447 + if off >= lenmsg {
448 + return "", lenmsg, ErrBuf
449 + }
450 + c1 := msg[off]
451 + off++
452 + if ptr == 0 {
453 + off1 = off
454 + }
455 + if ptr++; ptr > 10 {
456 + return "", lenmsg, &Error{err: "too many compression pointers"}
457 + }
458 + off = (c^0xC0)<<8 | int(c1)
459 + default:
460 + // 0x80 and 0x40 are reserved
461 + return "", lenmsg, ErrRdata
462 + }
463 + }
464 + if ptr == 0 {
465 + off1 = off
466 + }
467 + return string(s), off1, nil
468 +}
469 +
470 +func packTxt(txt []string, msg []byte, offset int, tmp []byte) (int, error) {
471 + var err error
472 + if len(txt) == 0 {
473 + if offset >= len(msg) {
474 + return offset, ErrBuf
475 + }
476 + msg[offset] = 0
477 + return offset, nil
478 + }
479 + for i := range txt {
480 + if len(txt[i]) > len(tmp) {
481 + return offset, ErrBuf
482 + }
483 + offset, err = packTxtString(txt[i], msg, offset, tmp)
484 + if err != nil {
485 + return offset, err
486 + }
487 + }
488 + return offset, err
489 +}
490 +
491 +func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
492 + lenByteOffset := offset
493 + if offset >= len(msg) {
494 + return offset, ErrBuf
495 + }
496 + offset++
497 + bs := tmp[:len(s)]
498 + copy(bs, s)
499 + for i := 0; i < len(bs); i++ {
500 + if len(msg) <= offset {
501 + return offset, ErrBuf
502 + }
503 + if bs[i] == '\\' {
504 + i++
505 + if i == len(bs) {
506 + break
507 + }
508 + // check for \DDD
509 + if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
510 + msg[offset] = dddToByte(bs[i:])
511 + i += 2
512 + } else if bs[i] == 't' {
513 + msg[offset] = '\t'
514 + } else if bs[i] == 'r' {
515 + msg[offset] = '\r'
516 + } else if bs[i] == 'n' {
517 + msg[offset] = '\n'
518 + } else {
519 + msg[offset] = bs[i]
520 + }
521 + } else {
522 + msg[offset] = bs[i]
523 + }
524 + offset++
525 + }
526 + l := offset - lenByteOffset - 1
527 + if l > 255 {
528 + return offset, &Error{err: "string exceeded 255 bytes in txt"}
529 + }
530 + msg[lenByteOffset] = byte(l)
531 + return offset, nil
532 +}
533 +
534 +func unpackTxt(msg []byte, offset, rdend int) ([]string, int, error) {
535 + var err error
536 + var ss []string
537 + var s string
538 + for offset < rdend && err == nil {
539 + s, offset, err = unpackTxtString(msg, offset)
540 + if err == nil {
541 + ss = append(ss, s)
542 + }
543 + }
544 + return ss, offset, err
545 +}
546 +
547 +func unpackTxtString(msg []byte, offset int) (string, int, error) {
548 + if offset+1 > len(msg) {
549 + return "", offset, &Error{err: "overflow unpacking txt"}
550 + }
551 + l := int(msg[offset])
552 + if offset+l+1 > len(msg) {
553 + return "", offset, &Error{err: "overflow unpacking txt"}
554 + }
555 + s := make([]byte, 0, l)
556 + for _, b := range msg[offset+1 : offset+1+l] {
557 + switch b {
558 + case '"', '\\':
559 + s = append(s, '\\', b)
560 + case '\t':
561 + s = append(s, `\t`...)
562 + case '\r':
563 + s = append(s, `\r`...)
564 + case '\n':
565 + s = append(s, `\n`...)
566 + default:
567 + if b < 32 || b > 127 { // unprintable
568 + var buf [3]byte
569 + bufs := strconv.AppendInt(buf[:0], int64(b), 10)
570 + s = append(s, '\\')
571 + for i := 0; i < 3-len(bufs); i++ {
572 + s = append(s, '0')
573 + }
574 + for _, r := range bufs {
575 + s = append(s, r)
576 + }
577 + } else {
578 + s = append(s, b)
579 + }
580 + }
581 + }
582 + offset += 1 + l
583 + return string(s), offset, nil
584 +}
585 +
586 +// Pack a reflect.StructValue into msg. Struct members can only be uint8, uint16, uint32, string,
587 +// slices and other (often anonymous) structs.
588 +func packStructValue(val reflect.Value, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
589 + var txtTmp []byte
590 + lenmsg := len(msg)
591 + numfield := val.NumField()
592 + for i := 0; i < numfield; i++ {
593 + typefield := val.Type().Field(i)
594 + if typefield.Tag == `dns:"-"` {
595 + continue
596 + }
597 + switch fv := val.Field(i); fv.Kind() {
598 + default:
599 + return lenmsg, &Error{err: "bad kind packing"}
600 + case reflect.Interface:
601 + // PrivateRR is the only RR implementation that has interface field.
602 + // therefore it's expected that this interface would be PrivateRdata
603 + switch data := fv.Interface().(type) {
604 + case PrivateRdata:
605 + n, err := data.Pack(msg[off:])
606 + if err != nil {
607 + return lenmsg, err
608 + }
609 + off += n
610 + default:
611 + return lenmsg, &Error{err: "bad kind interface packing"}
612 + }
613 + case reflect.Slice:
614 + switch typefield.Tag {
615 + default:
616 + return lenmsg, &Error{"bad tag packing slice: " + typefield.Tag.Get("dns")}
617 + case `dns:"domain-name"`:
618 + for j := 0; j < val.Field(i).Len(); j++ {
619 + element := val.Field(i).Index(j).String()
620 + off, err = PackDomainName(element, msg, off, compression, false && compress)
621 + if err != nil {
622 + return lenmsg, err
623 + }
624 + }
625 + case `dns:"txt"`:
626 + if txtTmp == nil {
627 + txtTmp = make([]byte, 256*4+1)
628 + }
629 + off, err = packTxt(fv.Interface().([]string), msg, off, txtTmp)
630 + if err != nil {
631 + return lenmsg, err
632 + }
633 + case `dns:"opt"`: // edns
634 + for j := 0; j < val.Field(i).Len(); j++ {
635 + element := val.Field(i).Index(j).Interface()
636 + b, e := element.(EDNS0).pack()
637 + if e != nil {
638 + return lenmsg, &Error{err: "overflow packing opt"}
639 + }
640 + // Option code
641 + msg[off], msg[off+1] = packUint16(element.(EDNS0).Option())
642 + // Length
643 + msg[off+2], msg[off+3] = packUint16(uint16(len(b)))
644 + off += 4
645 + if off+len(b) > lenmsg {
646 + copy(msg[off:], b)
647 + off = lenmsg
648 + continue
649 + }
650 + // Actual data
651 + copy(msg[off:off+len(b)], b)
652 + off += len(b)
653 + }
654 + case `dns:"a"`:
655 + if val.Type().String() == "dns.IPSECKEY" {
656 + // Field(2) is GatewayType, must be 1
657 + if val.Field(2).Uint() != 1 {
658 + continue
659 + }
660 + }
661 + // It must be a slice of 4, even if it is 16, we encode
662 + // only the first 4
663 + if off+net.IPv4len > lenmsg {
664 + return lenmsg, &Error{err: "overflow packing a"}
665 + }
666 + switch fv.Len() {
667 + case net.IPv6len:
668 + msg[off] = byte(fv.Index(12).Uint())
669 + msg[off+1] = byte(fv.Index(13).Uint())
670 + msg[off+2] = byte(fv.Index(14).Uint())
671 + msg[off+3] = byte(fv.Index(15).Uint())
672 + off += net.IPv4len
673 + case net.IPv4len:
674 + msg[off] = byte(fv.Index(0).Uint())
675 + msg[off+1] = byte(fv.Index(1).Uint())
676 + msg[off+2] = byte(fv.Index(2).Uint())
677 + msg[off+3] = byte(fv.Index(3).Uint())
678 + off += net.IPv4len
679 + case 0:
680 + // Allowed, for dynamic updates
681 + default:
682 + return lenmsg, &Error{err: "overflow packing a"}
683 + }
684 + case `dns:"aaaa"`:
685 + if val.Type().String() == "dns.IPSECKEY" {
686 + // Field(2) is GatewayType, must be 2
687 + if val.Field(2).Uint() != 2 {
688 + continue
689 + }
690 + }
691 + if fv.Len() == 0 {
692 + break
693 + }
694 + if fv.Len() > net.IPv6len || off+fv.Len() > lenmsg {
695 + return lenmsg, &Error{err: "overflow packing aaaa"}
696 + }
697 + for j := 0; j < net.IPv6len; j++ {
698 + msg[off] = byte(fv.Index(j).Uint())
699 + off++
700 + }
701 + case `dns:"wks"`:
702 + // TODO(miek): this is wrong should be lenrd
703 + if off == lenmsg {
704 + break // dyn. updates
705 + }
706 + if val.Field(i).Len() == 0 {
707 + break
708 + }
709 + var bitmapbyte uint16
710 + for j := 0; j < val.Field(i).Len(); j++ {
711 + serv := uint16((fv.Index(j).Uint()))
712 + bitmapbyte = uint16(serv / 8)
713 + if int(bitmapbyte) > lenmsg {
714 + return lenmsg, &Error{err: "overflow packing wks"}
715 + }
716 + bit := uint16(serv) - bitmapbyte*8
717 + msg[bitmapbyte] = byte(1 << (7 - bit))
718 + }
719 + off += int(bitmapbyte)
720 + case `dns:"nsec"`: // NSEC/NSEC3
721 + // This is the uint16 type bitmap
722 + if val.Field(i).Len() == 0 {
723 + // Do absolutely nothing
724 + break
725 + }
726 +
727 + lastwindow := uint16(0)
728 + length := uint16(0)
729 + if off+2 > lenmsg {
730 + return lenmsg, &Error{err: "overflow packing nsecx"}
731 + }
732 + for j := 0; j < val.Field(i).Len(); j++ {
733 + t := uint16((fv.Index(j).Uint()))
734 + window := uint16(t / 256)
735 + if lastwindow != window {
736 + // New window, jump to the new offset
737 + off += int(length) + 3
738 + if off > lenmsg {
739 + return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
740 + }
741 + }
742 + length = (t - window*256) / 8
743 + bit := t - (window * 256) - (length * 8)
744 + if off+2+int(length) > lenmsg {
745 + return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
746 + }
747 +
748 + // Setting the window #
749 + msg[off] = byte(window)
750 + // Setting the octets length
751 + msg[off+1] = byte(length + 1)
752 + // Setting the bit value for the type in the right octet
753 + msg[off+2+int(length)] |= byte(1 << (7 - bit))
754 + lastwindow = window
755 + }
756 + off += 2 + int(length)
757 + off++
758 + if off > lenmsg {
759 + return lenmsg, &Error{err: "overflow packing nsecx bitmap"}
760 + }
761 + }
762 + case reflect.Struct:
763 + off, err = packStructValue(fv, msg, off, compression, compress)
764 + if err != nil {
765 + return lenmsg, err
766 + }
767 + case reflect.Uint8:
768 + if off+1 > lenmsg {
769 + return lenmsg, &Error{err: "overflow packing uint8"}
770 + }
771 + msg[off] = byte(fv.Uint())
772 + off++
773 + case reflect.Uint16:
774 + if off+2 > lenmsg {
775 + return lenmsg, &Error{err: "overflow packing uint16"}
776 + }
777 + i := fv.Uint()
778 + msg[off] = byte(i >> 8)
779 + msg[off+1] = byte(i)
780 + off += 2
781 + case reflect.Uint32:
782 + if off+4 > lenmsg {
783 + return lenmsg, &Error{err: "overflow packing uint32"}
784 + }
785 + i := fv.Uint()
786 + msg[off] = byte(i >> 24)
787 + msg[off+1] = byte(i >> 16)
788 + msg[off+2] = byte(i >> 8)
789 + msg[off+3] = byte(i)
790 + off += 4
791 + case reflect.Uint64:
792 + switch typefield.Tag {
793 + default:
794 + if off+8 > lenmsg {
795 + return lenmsg, &Error{err: "overflow packing uint64"}
796 + }
797 + i := fv.Uint()
798 + msg[off] = byte(i >> 56)
799 + msg[off+1] = byte(i >> 48)
800 + msg[off+2] = byte(i >> 40)
801 + msg[off+3] = byte(i >> 32)
802 + msg[off+4] = byte(i >> 24)
803 + msg[off+5] = byte(i >> 16)
804 + msg[off+6] = byte(i >> 8)
805 + msg[off+7] = byte(i)
806 + off += 8
807 + case `dns:"uint48"`:
808 + // Used in TSIG, where it stops at 48 bits, so we discard the upper 16
809 + if off+6 > lenmsg {
810 + return lenmsg, &Error{err: "overflow packing uint64 as uint48"}
811 + }
812 + i := fv.Uint()
813 + msg[off] = byte(i >> 40)
814 + msg[off+1] = byte(i >> 32)
815 + msg[off+2] = byte(i >> 24)
816 + msg[off+3] = byte(i >> 16)
817 + msg[off+4] = byte(i >> 8)
818 + msg[off+5] = byte(i)
819 + off += 6
820 + }
821 + case reflect.String:
822 + // There are multiple string encodings.
823 + // The tag distinguishes ordinary strings from domain names.
824 + s := fv.String()
825 + switch typefield.Tag {
826 + default:
827 + return lenmsg, &Error{"bad tag packing string: " + typefield.Tag.Get("dns")}
828 + case `dns:"base64"`:
829 + b64, e := fromBase64([]byte(s))
830 + if e != nil {
831 + return lenmsg, e
832 + }
833 + copy(msg[off:off+len(b64)], b64)
834 + off += len(b64)
835 + case `dns:"domain-name"`:
836 + if val.Type().String() == "dns.IPSECKEY" {
837 + // Field(2) is GatewayType, 1 and 2 or used for addresses
838 + x := val.Field(2).Uint()
839 + if x == 1 || x == 2 {
840 + continue
841 + }
842 + }
843 + if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil {
844 + return lenmsg, err
845 + }
846 + case `dns:"cdomain-name"`:
847 + if off, err = PackDomainName(s, msg, off, compression, true && compress); err != nil {
848 + return lenmsg, err
849 + }
850 + case `dns:"size-base32"`:
851 + // This is purely for NSEC3 atm, the previous byte must
852 + // holds the length of the encoded string. As NSEC3
853 + // is only defined to SHA1, the hashlength is 20 (160 bits)
854 + msg[off-1] = 20
855 + fallthrough
856 + case `dns:"base32"`:
857 + b32, e := fromBase32([]byte(s))
858 + if e != nil {
859 + return lenmsg, e
860 + }
861 + copy(msg[off:off+len(b32)], b32)
862 + off += len(b32)
863 + case `dns:"size-hex"`:
864 + fallthrough
865 + case `dns:"hex"`:
866 + // There is no length encoded here
867 + h, e := hex.DecodeString(s)
868 + if e != nil {
869 + return lenmsg, e
870 + }
871 + if off+hex.DecodedLen(len(s)) > lenmsg {
872 + return lenmsg, &Error{err: "overflow packing hex"}
873 + }
874 + copy(msg[off:off+hex.DecodedLen(len(s))], h)
875 + off += hex.DecodedLen(len(s))
876 + case `dns:"size"`:
877 + // the size is already encoded in the RR, we can safely use the
878 + // length of string. String is RAW (not encoded in hex, nor base64)
879 + copy(msg[off:off+len(s)], s)
880 + off += len(s)
881 + case `dns:"txt"`:
882 + fallthrough
883 + case "":
884 + if txtTmp == nil {
885 + txtTmp = make([]byte, 256*4+1)
886 + }
887 + off, err = packTxtString(fv.String(), msg, off, txtTmp)
888 + if err != nil {
889 + return lenmsg, err
890 + }
891 + }
892 + }
893 + }
894 + return off, nil
895 +}
896 +
897 +func structValue(any interface{}) reflect.Value {
898 + return reflect.ValueOf(any).Elem()
899 +}
900 +
901 +// PackStruct packs any structure to wire format.
902 +func PackStruct(any interface{}, msg []byte, off int) (off1 int, err error) {
903 + off, err = packStructValue(structValue(any), msg, off, nil, false)
904 + return off, err
905 +}
906 +
907 +func packStructCompress(any interface{}, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
908 + off, err = packStructValue(structValue(any), msg, off, compression, compress)
909 + return off, err
910 +}
911 +
912 +// TODO(miek): Fix use of rdlength here
913 +
914 +// Unpack a reflect.StructValue from msg.
915 +// Same restrictions as packStructValue.
916 +func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) {
917 + var lenrd int
918 + lenmsg := len(msg)
919 + for i := 0; i < val.NumField(); i++ {
920 + if lenrd != 0 && lenrd == off {
921 + break
922 + }
923 + if off > lenmsg {
924 + return lenmsg, &Error{"bad offset unpacking"}
925 + }
926 + switch fv := val.Field(i); fv.Kind() {
927 + default:
928 + return lenmsg, &Error{err: "bad kind unpacking"}
929 + case reflect.Interface:
930 + // PrivateRR is the only RR implementation that has interface field.
931 + // therefore it's expected that this interface would be PrivateRdata
932 + switch data := fv.Interface().(type) {
933 + case PrivateRdata:
934 + n, err := data.Unpack(msg[off:lenrd])
935 + if err != nil {
936 + return lenmsg, err
937 + }
938 + off += n
939 + default:
940 + return lenmsg, &Error{err: "bad kind interface unpacking"}
941 + }
942 + case reflect.Slice:
943 + switch val.Type().Field(i).Tag {
944 + default:
945 + return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")}
946 + case `dns:"domain-name"`:
947 + // HIP record slice of name (or none)
948 + servers := make([]string, 0)
949 + var s string
950 + for off < lenrd {
951 + s, off, err = UnpackDomainName(msg, off)
952 + if err != nil {
953 + return lenmsg, err
954 + }
955 + servers = append(servers, s)
956 + }
957 + fv.Set(reflect.ValueOf(servers))
958 + case `dns:"txt"`:
959 + if off == lenmsg || lenrd == off {
960 + break
961 + }
962 + var txt []string
963 + txt, off, err = unpackTxt(msg, off, lenrd)
964 + if err != nil {
965 + return lenmsg, err
966 + }
967 + fv.Set(reflect.ValueOf(txt))
968 + case `dns:"opt"`: // edns0
969 + if off == lenrd {
970 + // This is an EDNS0 (OPT Record) with no rdata
971 + // We can safely return here.
972 + break
973 + }
974 + edns := make([]EDNS0, 0)
975 + Option:
976 + code := uint16(0)
977 + if off+2 > lenmsg {
978 + return lenmsg, &Error{err: "overflow unpacking opt"}
979 + }
980 + code, off = unpackUint16(msg, off)
981 + optlen, off1 := unpackUint16(msg, off)
982 + if off1+int(optlen) > lenrd {
983 + return lenmsg, &Error{err: "overflow unpacking opt"}
984 + }
985 + switch code {
986 + case EDNS0NSID:
987 + e := new(EDNS0_NSID)
988 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
989 + return lenmsg, err
990 + }
991 + edns = append(edns, e)
992 + off = off1 + int(optlen)
993 + case EDNS0SUBNET, EDNS0SUBNETDRAFT:
994 + e := new(EDNS0_SUBNET)
995 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
996 + return lenmsg, err
997 + }
998 + edns = append(edns, e)
999 + off = off1 + int(optlen)
1000 + if code == EDNS0SUBNETDRAFT {
1001 + e.DraftOption = true
1002 + }
1003 + case EDNS0UL:
1004 + e := new(EDNS0_UL)
1005 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
1006 + return lenmsg, err
1007 + }
1008 + edns = append(edns, e)
1009 + off = off1 + int(optlen)
1010 + case EDNS0LLQ:
1011 + e := new(EDNS0_LLQ)
1012 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
1013 + return lenmsg, err
1014 + }
1015 + edns = append(edns, e)
1016 + off = off1 + int(optlen)
1017 + case EDNS0DAU:
1018 + e := new(EDNS0_DAU)
1019 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
1020 + return lenmsg, err
1021 + }
1022 + edns = append(edns, e)
1023 + off = off1 + int(optlen)
1024 + case EDNS0DHU:
1025 + e := new(EDNS0_DHU)
1026 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
1027 + return lenmsg, err
1028 + }
1029 + edns = append(edns, e)
1030 + off = off1 + int(optlen)
1031 + case EDNS0N3U:
1032 + e := new(EDNS0_N3U)
1033 + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil {
1034 + return lenmsg, err
1035 + }
1036 + edns = append(edns, e)
1037 + off = off1 + int(optlen)
1038 + default:
1039 + // do nothing?
1040 + off = off1 + int(optlen)
1041 + }
1042 + if off < lenrd {
1043 + goto Option
1044 + }
1045 + fv.Set(reflect.ValueOf(edns))
1046 + case `dns:"a"`:
1047 + if val.Type().String() == "dns.IPSECKEY" {
1048 + // Field(2) is GatewayType, must be 1
1049 + if val.Field(2).Uint() != 1 {
1050 + continue
1051 + }
1052 + }
1053 + if off == lenrd {
1054 + break // dyn. update
1055 + }
1056 + if off+net.IPv4len > lenrd || off+net.IPv4len > lenmsg {
1057 + return lenmsg, &Error{err: "overflow unpacking a"}
1058 + }
1059 + fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3])))
1060 + off += net.IPv4len
1061 + case `dns:"aaaa"`:
1062 + if val.Type().String() == "dns.IPSECKEY" {
1063 + // Field(2) is GatewayType, must be 2
1064 + if val.Field(2).Uint() != 2 {
1065 + continue
1066 + }
1067 + }
1068 + if off == lenrd {
1069 + break
1070 + }
1071 + if off+net.IPv6len > lenrd || off+net.IPv6len > lenmsg {
1072 + return lenmsg, &Error{err: "overflow unpacking aaaa"}
1073 + }
1074 + fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4],
1075 + msg[off+5], msg[off+6], msg[off+7], msg[off+8], msg[off+9], msg[off+10],
1076 + msg[off+11], msg[off+12], msg[off+13], msg[off+14], msg[off+15]}))
1077 + off += net.IPv6len
1078 + case `dns:"wks"`:
1079 + // Rest of the record is the bitmap
1080 + serv := make([]uint16, 0)
1081 + j := 0
1082 + for off < lenrd {
1083 + if off+1 > lenmsg {
1084 + return lenmsg, &Error{err: "overflow unpacking wks"}
1085 + }
1086 + b := msg[off]
1087 + // Check the bits one by one, and set the type
1088 + if b&0x80 == 0x80 {
1089 + serv = append(serv, uint16(j*8+0))
1090 + }
1091 + if b&0x40 == 0x40 {
1092 + serv = append(serv, uint16(j*8+1))
1093 + }
1094 + if b&0x20 == 0x20 {
1095 + serv = append(serv, uint16(j*8+2))
1096 + }
1097 + if b&0x10 == 0x10 {
1098 + serv = append(serv, uint16(j*8+3))
1099 + }
1100 + if b&0x8 == 0x8 {
1101 + serv = append(serv, uint16(j*8+4))
1102 + }
1103 + if b&0x4 == 0x4 {
1104 + serv = append(serv, uint16(j*8+5))
1105 + }
1106 + if b&0x2 == 0x2 {
1107 + serv = append(serv, uint16(j*8+6))
1108 + }
1109 + if b&0x1 == 0x1 {
1110 + serv = append(serv, uint16(j*8+7))
1111 + }
1112 + j++
1113 + off++
1114 + }
1115 + fv.Set(reflect.ValueOf(serv))
1116 + case `dns:"nsec"`: // NSEC/NSEC3
1117 + if off == lenrd {
1118 + break
1119 + }
1120 + // Rest of the record is the type bitmap
1121 + if off+2 > lenrd || off+2 > lenmsg {
1122 + return lenmsg, &Error{err: "overflow unpacking nsecx"}
1123 + }
1124 + nsec := make([]uint16, 0)
1125 + length := 0
1126 + window := 0
1127 + for off+2 < lenrd {
1128 + window = int(msg[off])
1129 + length = int(msg[off+1])
1130 + //println("off, windows, length, end", off, window, length, endrr)
1131 + if length == 0 {
1132 + // A length window of zero is strange. If there
1133 + // the window should not have been specified. Bail out
1134 + // println("dns: length == 0 when unpacking NSEC")
1135 + return lenmsg, &Error{err: "overflow unpacking nsecx"}
1136 + }
1137 + if length > 32 {
1138 + return lenmsg, &Error{err: "overflow unpacking nsecx"}
1139 + }
1140 +
1141 + // Walk the bytes in the window - and check the bit settings...
1142 + off += 2
1143 + for j := 0; j < length; j++ {
1144 + if off+j+1 > lenmsg {
1145 + return lenmsg, &Error{err: "overflow unpacking nsecx"}
1146 + }
1147 + b := msg[off+j]
1148 + // Check the bits one by one, and set the type
1149 + if b&0x80 == 0x80 {
1150 + nsec = append(nsec, uint16(window*256+j*8+0))
1151 + }
1152 + if b&0x40 == 0x40 {
1153 + nsec = append(nsec, uint16(window*256+j*8+1))
1154 + }
1155 + if b&0x20 == 0x20 {
1156 + nsec = append(nsec, uint16(window*256+j*8+2))
1157 + }
1158 + if b&0x10 == 0x10 {
1159 + nsec = append(nsec, uint16(window*256+j*8+3))
1160 + }
1161 + if b&0x8 == 0x8 {
1162 + nsec = append(nsec, uint16(window*256+j*8+4))
1163 + }
1164 + if b&0x4 == 0x4 {
1165 + nsec = append(nsec, uint16(window*256+j*8+5))
1166 + }
1167 + if b&0x2 == 0x2 {
1168 + nsec = append(nsec, uint16(window*256+j*8+6))
1169 + }
1170 + if b&0x1 == 0x1 {
1171 + nsec = append(nsec, uint16(window*256+j*8+7))
1172 + }
1173 + }
1174 + off += length
1175 + }
1176 + fv.Set(reflect.ValueOf(nsec))
1177 + }
1178 + case reflect.Struct:
1179 + off, err = unpackStructValue(fv, msg, off)
1180 + if err != nil {
1181 + return lenmsg, err
1182 + }
1183 + if val.Type().Field(i).Name == "Hdr" {
1184 + lenrd = off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint())
1185 + }
1186 + case reflect.Uint8:
1187 + if off == lenmsg {
1188 + break
1189 + }
1190 + if off+1 > lenmsg {
1191 + return lenmsg, &Error{err: "overflow unpacking uint8"}
1192 + }
1193 + fv.SetUint(uint64(uint8(msg[off])))
1194 + off++
1195 + case reflect.Uint16:
1196 + if off == lenmsg {
1197 + break
1198 + }
1199 + var i uint16
1200 + if off+2 > lenmsg {
1201 + return lenmsg, &Error{err: "overflow unpacking uint16"}
1202 + }
1203 + i, off = unpackUint16(msg, off)
1204 + fv.SetUint(uint64(i))
1205 + case reflect.Uint32:
1206 + if off == lenmsg {
1207 + break
1208 + }
1209 + if off+4 > lenmsg {
1210 + return lenmsg, &Error{err: "overflow unpacking uint32"}
1211 + }
1212 + fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])))
1213 + off += 4
1214 + case reflect.Uint64:
1215 + switch val.Type().Field(i).Tag {
1216 + default:
1217 + if off+8 > lenmsg {
1218 + return lenmsg, &Error{err: "overflow unpacking uint64"}
1219 + }
1220 + fv.SetUint(uint64(uint64(msg[off])<<56 | uint64(msg[off+1])<<48 | uint64(msg[off+2])<<40 |
1221 + uint64(msg[off+3])<<32 | uint64(msg[off+4])<<24 | uint64(msg[off+5])<<16 | uint64(msg[off+6])<<8 | uint64(msg[off+7])))
1222 + off += 8
1223 + case `dns:"uint48"`:
1224 + // Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
1225 + if off+6 > lenmsg {
1226 + return lenmsg, &Error{err: "overflow unpacking uint64 as uint48"}
1227 + }
1228 + fv.SetUint(uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
1229 + uint64(msg[off+4])<<8 | uint64(msg[off+5])))
1230 + off += 6
1231 + }
1232 + case reflect.String:
1233 + var s string
1234 + if off == lenmsg {
1235 + break
1236 + }
1237 + switch val.Type().Field(i).Tag {
1238 + default:
1239 + return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")}
1240 + case `dns:"hex"`:
1241 + hexend := lenrd
1242 + if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
1243 + hexend = off + int(val.FieldByName("HitLength").Uint())
1244 + }
1245 + if hexend > lenrd || hexend > lenmsg {
1246 + return lenmsg, &Error{err: "overflow unpacking hex"}
1247 + }
1248 + s = hex.EncodeToString(msg[off:hexend])
1249 + off = hexend
1250 + case `dns:"base64"`:
1251 + // Rest of the RR is base64 encoded value
1252 + b64end := lenrd
1253 + if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) {
1254 + b64end = off + int(val.FieldByName("PublicKeyLength").Uint())
1255 + }
1256 + if b64end > lenrd || b64end > lenmsg {
1257 + return lenmsg, &Error{err: "overflow unpacking base64"}
1258 + }
1259 + s = toBase64(msg[off:b64end])
1260 + off = b64end
1261 + case `dns:"cdomain-name"`:
1262 + fallthrough
1263 + case `dns:"domain-name"`:
1264 + if val.Type().String() == "dns.IPSECKEY" {
1265 + // Field(2) is GatewayType, 1 and 2 or used for addresses
1266 + x := val.Field(2).Uint()
1267 + if x == 1 || x == 2 {
1268 + continue
1269 + }
1270 + }
1271 + if off == lenmsg {
1272 + // zero rdata foo, OK for dyn. updates
1273 + break
1274 + }
1275 + s, off, err = UnpackDomainName(msg, off)
1276 + if err != nil {
1277 + return lenmsg, err
1278 + }
1279 + case `dns:"size-base32"`:
1280 + var size int
1281 + switch val.Type().Name() {
1282 + case "NSEC3":
1283 + switch val.Type().Field(i).Name {
1284 + case "NextDomain":
1285 + name := val.FieldByName("HashLength")
1286 + size = int(name.Uint())
1287 + }
1288 + }
1289 + if off+size > lenmsg {
1290 + return lenmsg, &Error{err: "overflow unpacking base32"}
1291 + }
1292 + s = toBase32(msg[off : off+size])
1293 + off += size
1294 + case `dns:"size-hex"`:
1295 + // a "size" string, but it must be encoded in hex in the string
1296 + var size int
1297 + switch val.Type().Name() {
1298 + case "NSEC3":
1299 + switch val.Type().Field(i).Name {
1300 + case "Salt":
1301 + name := val.FieldByName("SaltLength")
1302 + size = int(name.Uint())
1303 + case "NextDomain":
1304 + name := val.FieldByName("HashLength")
1305 + size = int(name.Uint())
1306 + }
1307 + case "TSIG":
1308 + switch val.Type().Field(i).Name {
1309 + case "MAC":
1310 + name := val.FieldByName("MACSize")
1311 + size = int(name.Uint())
1312 + case "OtherData":
1313 + name := val.FieldByName("OtherLen")
1314 + size = int(name.Uint())
1315 + }
1316 + }
1317 + if off+size > lenmsg {
1318 + return lenmsg, &Error{err: "overflow unpacking hex"}
1319 + }
1320 + s = hex.EncodeToString(msg[off : off+size])
1321 + off += size
1322 + case `dns:"txt"`:
1323 + fallthrough
1324 + case "":
1325 + s, off, err = unpackTxtString(msg, off)
1326 + }
1327 + fv.SetString(s)
1328 + }
1329 + }
1330 + return off, nil
1331 +}
1332 +
1333 +// Helpers for dealing with escaped bytes
1334 +func isDigit(b byte) bool { return b >= '0' && b <= '9' }
1335 +
1336 +func dddToByte(s []byte) byte {
1337 + return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
1338 +}
1339 +
1340 +// UnpackStruct unpacks a binary message from offset off to the interface
1341 +// value given.
1342 +func UnpackStruct(any interface{}, msg []byte, off int) (int, error) {
1343 + return unpackStructValue(structValue(any), msg, off)
1344 +}
1345 +
1346 +// Helper function for packing and unpacking
1347 +func intToBytes(i *big.Int, length int) []byte {
1348 + buf := i.Bytes()
1349 + if len(buf) < length {
1350 + b := make([]byte, length)
1351 + copy(b[length-len(buf):], buf)
1352 + return b
1353 + }
1354 + return buf
1355 +}
1356 +
1357 +func unpackUint16(msg []byte, off int) (uint16, int) {
1358 + return uint16(msg[off])<<8 | uint16(msg[off+1]), off + 2
1359 +}
1360 +
1361 +func packUint16(i uint16) (byte, byte) {
1362 + return byte(i >> 8), byte(i)
1363 +}
1364 +
1365 +func toBase32(b []byte) string {
1366 + return base32.HexEncoding.EncodeToString(b)
1367 +}
1368 +
1369 +func fromBase32(s []byte) (buf []byte, err error) {
1370 + buflen := base32.HexEncoding.DecodedLen(len(s))
1371 + buf = make([]byte, buflen)
1372 + n, err := base32.HexEncoding.Decode(buf, s)
1373 + buf = buf[:n]
1374 + return
1375 +}
1376 +
1377 +func toBase64(b []byte) string {
1378 + return base64.StdEncoding.EncodeToString(b)
1379 +}
1380 +
1381 +func fromBase64(s []byte) (buf []byte, err error) {
1382 + buflen := base64.StdEncoding.DecodedLen(len(s))
1383 + buf = make([]byte, buflen)
1384 + n, err := base64.StdEncoding.Decode(buf, s)
1385 + buf = buf[:n]
1386 + return
1387 +}
1388 +
1389 +// PackRR packs a resource record rr into msg[off:].
1390 +// See PackDomainName for documentation about the compression.
1391 +func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
1392 + if rr == nil {
1393 + return len(msg), &Error{err: "nil rr"}
1394 + }
1395 +
1396 + off1, err = packStructCompress(rr, msg, off, compression, compress)
1397 + if err != nil {
1398 + return len(msg), err
1399 + }
1400 + if rawSetRdlength(msg, off, off1) {
1401 + return off1, nil
1402 + }
1403 + return off, ErrRdata
1404 +}
1405 +
1406 +// UnpackRR unpacks msg[off:] into an RR.
1407 +func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
1408 + // unpack just the header, to find the rr type and length
1409 + var h RR_Header
1410 + off0 := off
1411 + if off, err = UnpackStruct(&h, msg, off); err != nil {
1412 + return nil, len(msg), err
1413 + }
1414 + end := off + int(h.Rdlength)
1415 + // make an rr of that type and re-unpack.
1416 + mk, known := typeToRR[h.Rrtype]
1417 + if !known {
1418 + rr = new(RFC3597)
1419 + } else {
1420 + rr = mk()
1421 + }
1422 + off, err = UnpackStruct(rr, msg, off0)
1423 + if off != end {
1424 + return &h, end, &Error{err: "bad rdlength"}
1425 + }
1426 + return rr, off, err
1427 +}
1428 +
1429 +// Reverse a map
1430 +func reverseInt8(m map[uint8]string) map[string]uint8 {
1431 + n := make(map[string]uint8)
1432 + for u, s := range m {
1433 + n[s] = u
1434 + }
1435 + return n
1436 +}
1437 +
1438 +func reverseInt16(m map[uint16]string) map[string]uint16 {
1439 + n := make(map[string]uint16)
1440 + for u, s := range m {
1441 + n[s] = u
1442 + }
1443 + return n
1444 +}
1445 +
1446 +func reverseInt(m map[int]string) map[string]int {
1447 + n := make(map[string]int)
1448 + for u, s := range m {
1449 + n[s] = u
1450 + }
1451 + return n
1452 +}
1453 +
1454 +// Convert a MsgHdr to a string, with dig-like headers:
1455 +//
1456 +//;; opcode: QUERY, status: NOERROR, id: 48404
1457 +//
1458 +//;; flags: qr aa rd ra;
1459 +func (h *MsgHdr) String() string {
1460 + if h == nil {
1461 + return "<nil> MsgHdr"
1462 + }
1463 +
1464 + s := ";; opcode: " + OpcodeToString[h.Opcode]
1465 + s += ", status: " + RcodeToString[h.Rcode]
1466 + s += ", id: " + strconv.Itoa(int(h.Id)) + "\n"
1467 +
1468 + s += ";; flags:"
1469 + if h.Response {
1470 + s += " qr"
1471 + }
1472 + if h.Authoritative {
1473 + s += " aa"
1474 + }
1475 + if h.Truncated {
1476 + s += " tc"
1477 + }
1478 + if h.RecursionDesired {
1479 + s += " rd"
1480 + }
1481 + if h.RecursionAvailable {
1482 + s += " ra"
1483 + }
1484 + if h.Zero { // Hmm
1485 + s += " z"
1486 + }
1487 + if h.AuthenticatedData {
1488 + s += " ad"
1489 + }
1490 + if h.CheckingDisabled {
1491 + s += " cd"
1492 + }
1493 +
1494 + s += ";"
1495 + return s
1496 +}
1497 +
1498 +// Pack packs a Msg: it is converted to to wire format.
1499 +// If the dns.Compress is true the message will be in compressed wire format.
1500 +func (dns *Msg) Pack() (msg []byte, err error) {
1501 + return dns.PackBuffer(nil)
1502 +}
1503 +
1504 +// PackBuffer packs a Msg, using the given buffer buf. If buf is too small
1505 +// a new buffer is allocated.
1506 +func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
1507 + var dh Header
1508 + var compression map[string]int
1509 + if dns.Compress {
1510 + compression = make(map[string]int) // Compression pointer mappings
1511 + }
1512 +
1513 + if dns.Rcode < 0 || dns.Rcode > 0xFFF {
1514 + return nil, ErrRcode
1515 + }
1516 + if dns.Rcode > 0xF {
1517 + // Regular RCODE field is 4 bits
1518 + opt := dns.IsEdns0()
1519 + if opt == nil {
1520 + return nil, ErrExtendedRcode
1521 + }
1522 + opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
1523 + dns.Rcode &= 0xF
1524 + }
1525 +
1526 + // Convert convenient Msg into wire-like Header.
1527 + dh.Id = dns.Id
1528 + dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode)
1529 + if dns.Response {
1530 + dh.Bits |= _QR
1531 + }
1532 + if dns.Authoritative {
1533 + dh.Bits |= _AA
1534 + }
1535 + if dns.Truncated {
1536 + dh.Bits |= _TC
1537 + }
1538 + if dns.RecursionDesired {
1539 + dh.Bits |= _RD
1540 + }
1541 + if dns.RecursionAvailable {
1542 + dh.Bits |= _RA
1543 + }
1544 + if dns.Zero {
1545 + dh.Bits |= _Z
1546 + }
1547 + if dns.AuthenticatedData {
1548 + dh.Bits |= _AD
1549 + }
1550 + if dns.CheckingDisabled {
1551 + dh.Bits |= _CD
1552 + }
1553 +
1554 + // Prepare variable sized arrays.
1555 + question := dns.Question
1556 + answer := dns.Answer
1557 + ns := dns.Ns
1558 + extra := dns.Extra
1559 +
1560 + dh.Qdcount = uint16(len(question))
1561 + dh.Ancount = uint16(len(answer))
1562 + dh.Nscount = uint16(len(ns))
1563 + dh.Arcount = uint16(len(extra))
1564 +
1565 + // We need the uncompressed length here, because we first pack it and then compress it.
1566 + msg = buf
1567 + compress := dns.Compress
1568 + dns.Compress = false
1569 + if packLen := dns.Len() + 1; len(msg) < packLen {
1570 + msg = make([]byte, packLen)
1571 + }
1572 + dns.Compress = compress
1573 +
1574 + // Pack it in: header and then the pieces.
1575 + off := 0
1576 + off, err = packStructCompress(&dh, msg, off, compression, dns.Compress)
1577 + if err != nil {
1578 + return nil, err
1579 + }
1580 + for i := 0; i < len(question); i++ {
1581 + off, err = packStructCompress(&question[i], msg, off, compression, dns.Compress)
1582 + if err != nil {
1583 + return nil, err
1584 + }
1585 + }
1586 + for i := 0; i < len(answer); i++ {
1587 + off, err = PackRR(answer[i], msg, off, compression, dns.Compress)
1588 + if err != nil {
1589 + return nil, err
1590 + }
1591 + }
1592 + for i := 0; i < len(ns); i++ {
1593 + off, err = PackRR(ns[i], msg, off, compression, dns.Compress)
1594 + if err != nil {
1595 + return nil, err
1596 + }
1597 + }
1598 + for i := 0; i < len(extra); i++ {
1599 + off, err = PackRR(extra[i], msg, off, compression, dns.Compress)
1600 + if err != nil {
1601 + return nil, err
1602 + }
1603 + }
1604 + return msg[:off], nil
1605 +}
1606 +
1607 +// Unpack unpacks a binary message to a Msg structure.
1608 +func (dns *Msg) Unpack(msg []byte) (err error) {
1609 + // Header.
1610 + var dh Header
1611 + off := 0
1612 + if off, err = UnpackStruct(&dh, msg, off); err != nil {
1613 + return err
1614 + }
1615 + dns.Id = dh.Id
1616 + dns.Response = (dh.Bits & _QR) != 0
1617 + dns.Opcode = int(dh.Bits>>11) & 0xF
1618 + dns.Authoritative = (dh.Bits & _AA) != 0
1619 + dns.Truncated = (dh.Bits & _TC) != 0
1620 + dns.RecursionDesired = (dh.Bits & _RD) != 0
1621 + dns.RecursionAvailable = (dh.Bits & _RA) != 0
1622 + dns.Zero = (dh.Bits & _Z) != 0
1623 + dns.AuthenticatedData = (dh.Bits & _AD) != 0
1624 + dns.CheckingDisabled = (dh.Bits & _CD) != 0
1625 + dns.Rcode = int(dh.Bits & 0xF)
1626 +
1627 + // Arrays.
1628 + dns.Question = make([]Question, dh.Qdcount)
1629 + dns.Answer = make([]RR, dh.Ancount)
1630 + dns.Ns = make([]RR, dh.Nscount)
1631 + dns.Extra = make([]RR, dh.Arcount)
1632 +
1633 + for i := 0; i < len(dns.Question); i++ {
1634 + off, err = UnpackStruct(&dns.Question[i], msg, off)
1635 + if err != nil {
1636 + return err
1637 + }
1638 + }
1639 + // If we see a TC bit being set we return here, without
1640 + // an error, because technically it isn't an error. So return
1641 + // without parsing the potentially corrupt packet and hitting an error.
1642 + // TODO(miek): this isn't the best strategy!
1643 + if dns.Truncated {
1644 + dns.Answer = nil
1645 + dns.Ns = nil
1646 + dns.Extra = nil
1647 + return nil
1648 + }
1649 + for i := 0; i < len(dns.Answer); i++ {
1650 + dns.Answer[i], off, err = UnpackRR(msg, off)
1651 + if err != nil {
1652 + return err
1653 + }
1654 + }
1655 + for i := 0; i < len(dns.Ns); i++ {
1656 + dns.Ns[i], off, err = UnpackRR(msg, off)
1657 + if err != nil {
1658 + return err
1659 + }
1660 + }
1661 + for i := 0; i < len(dns.Extra); i++ {
1662 + dns.Extra[i], off, err = UnpackRR(msg, off)
1663 + if err != nil {
1664 + return err
1665 + }
1666 + }
1667 + if off != len(msg) {
1668 + // TODO(miek) make this an error?
1669 + // use PackOpt to let people tell how detailed the error reporting should be?
1670 + // println("dns: extra bytes in dns packet", off, "<", len(msg))
1671 + }
1672 + return nil
1673 +}
1674 +
1675 +// Convert a complete message to a string with dig-like output.
1676 +func (dns *Msg) String() string {
1677 + if dns == nil {
1678 + return "<nil> MsgHdr"
1679 + }
1680 + s := dns.MsgHdr.String() + " "
1681 + s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
1682 + s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
1683 + s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
1684 + s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
1685 + if len(dns.Question) > 0 {
1686 + s += "\n;; QUESTION SECTION:\n"
1687 + for i := 0; i < len(dns.Question); i++ {
1688 + s += dns.Question[i].String() + "\n"
1689 + }
1690 + }
1691 + if len(dns.Answer) > 0 {
1692 + s += "\n;; ANSWER SECTION:\n"
1693 + for i := 0; i < len(dns.Answer); i++ {
1694 + if dns.Answer[i] != nil {
1695 + s += dns.Answer[i].String() + "\n"
1696 + }
1697 + }
1698 + }
1699 + if len(dns.Ns) > 0 {
1700 + s += "\n;; AUTHORITY SECTION:\n"
1701 + for i := 0; i < len(dns.Ns); i++ {
1702 + if dns.Ns[i] != nil {
1703 + s += dns.Ns[i].String() + "\n"
1704 + }
1705 + }
1706 + }
1707 + if len(dns.Extra) > 0 {
1708 + s += "\n;; ADDITIONAL SECTION:\n"
1709 + for i := 0; i < len(dns.Extra); i++ {
1710 + if dns.Extra[i] != nil {
1711 + s += dns.Extra[i].String() + "\n"
1712 + }
1713 + }
1714 + }
1715 + return s
1716 +}
1717 +
1718 +// Len returns the message length when in (un)compressed wire format.
1719 +// If dns.Compress is true compression it is taken into account. Len()
1720 +// is provided to be a faster way to get the size of the resulting packet,
1721 +// than packing it, measuring the size and discarding the buffer.
1722 +func (dns *Msg) Len() int {
1723 + // We always return one more than needed.
1724 + l := 12 // Message header is always 12 bytes
1725 + var compression map[string]int
1726 + if dns.Compress {
1727 + compression = make(map[string]int)
1728 + }
1729 + for i := 0; i < len(dns.Question); i++ {
1730 + l += dns.Question[i].len()
1731 + if dns.Compress {
1732 + compressionLenHelper(compression, dns.Question[i].Name)
1733 + }
1734 + }
1735 + for i := 0; i < len(dns.Answer); i++ {
1736 + l += dns.Answer[i].len()
1737 + if dns.Compress {
1738 + k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
1739 + if ok {
1740 + l += 1 - k
1741 + }
1742 + compressionLenHelper(compression, dns.Answer[i].Header().Name)
1743 + k, ok = compressionLenSearchType(compression, dns.Answer[i])
1744 + if ok {
1745 + l += 1 - k
1746 + }
1747 + compressionLenHelperType(compression, dns.Answer[i])
1748 + }
1749 + }
1750 + for i := 0; i < len(dns.Ns); i++ {
1751 + l += dns.Ns[i].len()
1752 + if dns.Compress {
1753 + k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
1754 + if ok {
1755 + l += 1 - k
1756 + }
1757 + compressionLenHelper(compression, dns.Ns[i].Header().Name)
1758 + k, ok = compressionLenSearchType(compression, dns.Ns[i])
1759 + if ok {
1760 + l += 1 - k
1761 + }
1762 + compressionLenHelperType(compression, dns.Ns[i])
1763 + }
1764 + }
1765 + for i := 0; i < len(dns.Extra); i++ {
1766 + l += dns.Extra[i].len()
1767 + if dns.Compress {
1768 + k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
1769 + if ok {
1770 + l += 1 - k
1771 + }
1772 + compressionLenHelper(compression, dns.Extra[i].Header().Name)
1773 + k, ok = compressionLenSearchType(compression, dns.Extra[i])
1774 + if ok {
1775 + l += 1 - k
1776 + }
1777 + compressionLenHelperType(compression, dns.Extra[i])
1778 + }
1779 + }
1780 + return l
1781 +}
1782 +
1783 +// Put the parts of the name in the compression map.
1784 +func compressionLenHelper(c map[string]int, s string) {
1785 + pref := ""
1786 + lbs := Split(s)
1787 + for j := len(lbs) - 1; j >= 0; j-- {
1788 + pref = s[lbs[j]:]
1789 + if _, ok := c[pref]; !ok {
1790 + c[pref] = len(pref)
1791 + }
1792 + }
1793 +}
1794 +
1795 +// Look for each part in the compression map and returns its length,
1796 +// keep on searching so we get the longest match.
1797 +func compressionLenSearch(c map[string]int, s string) (int, bool) {
1798 + off := 0
1799 + end := false
1800 + if s == "" { // don't bork on bogus data
1801 + return 0, false
1802 + }
1803 + for {
1804 + if _, ok := c[s[off:]]; ok {
1805 + return len(s[off:]), true
1806 + }
1807 + if end {
1808 + break
1809 + }
1810 + off, end = NextLabel(s, off)
1811 + }
1812 + return 0, false
1813 +}
1814 +
1815 +// TODO(miek): should add all types, because the all can be *used* for compression.
1816 +func compressionLenHelperType(c map[string]int, r RR) {
1817 + switch x := r.(type) {
1818 + case *NS:
1819 + compressionLenHelper(c, x.Ns)
1820 + case *MX:
1821 + compressionLenHelper(c, x.Mx)
1822 + case *CNAME:
1823 + compressionLenHelper(c, x.Target)
1824 + case *PTR:
1825 + compressionLenHelper(c, x.Ptr)
1826 + case *SOA:
1827 + compressionLenHelper(c, x.Ns)
1828 + compressionLenHelper(c, x.Mbox)
1829 + case *MB:
1830 + compressionLenHelper(c, x.Mb)
1831 + case *MG:
1832 + compressionLenHelper(c, x.Mg)
1833 + case *MR:
1834 + compressionLenHelper(c, x.Mr)
1835 + case *MF:
1836 + compressionLenHelper(c, x.Mf)
1837 + case *MD:
1838 + compressionLenHelper(c, x.Md)
1839 + case *RT:
1840 + compressionLenHelper(c, x.Host)
1841 + case *MINFO:
1842 + compressionLenHelper(c, x.Rmail)
1843 + compressionLenHelper(c, x.Email)
1844 + case *AFSDB:
1845 + compressionLenHelper(c, x.Hostname)
1846 + }
1847 +}
1848 +
1849 +// Only search on compressing these types.
1850 +func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
1851 + switch x := r.(type) {
1852 + case *NS:
1853 + return compressionLenSearch(c, x.Ns)
1854 + case *MX:
1855 + return compressionLenSearch(c, x.Mx)
1856 + case *CNAME:
1857 + return compressionLenSearch(c, x.Target)
1858 + case *PTR:
1859 + return compressionLenSearch(c, x.Ptr)
1860 + case *SOA:
1861 + k, ok := compressionLenSearch(c, x.Ns)
1862 + k1, ok1 := compressionLenSearch(c, x.Mbox)
1863 + if !ok && !ok1 {
1864 + return 0, false
1865 + }
1866 + return k + k1, true
1867 + case *MB:
1868 + return compressionLenSearch(c, x.Mb)
1869 + case *MG:
1870 + return compressionLenSearch(c, x.Mg)
1871 + case *MR:
1872 + return compressionLenSearch(c, x.Mr)
1873 + case *MF:
1874 + return compressionLenSearch(c, x.Mf)
1875 + case *MD:
1876 + return compressionLenSearch(c, x.Md)
1877 + case *RT:
1878 + return compressionLenSearch(c, x.Host)
1879 + case *MINFO:
1880 + k, ok := compressionLenSearch(c, x.Rmail)
1881 + k1, ok1 := compressionLenSearch(c, x.Email)
1882 + if !ok && !ok1 {
1883 + return 0, false
1884 + }
1885 + return k + k1, true
1886 + case *AFSDB:
1887 + return compressionLenSearch(c, x.Hostname)
1888 + }
1889 + return 0, false
1890 +}
1891 +
1892 +// id returns a 16 bits random number to be used as a
1893 +// message id. The random provided should be good enough.
1894 +func id() uint16 {
1895 + return uint16(rand.Int()) ^ uint16(time.Now().Nanosecond())
1896 +}
1897 +
1898 +// Copy returns a new RR which is a deep-copy of r.
1899 +func Copy(r RR) RR {
1900 + r1 := r.copy()
1901 + return r1
1902 +}
1903 +
1904 +// Copy returns a new *Msg which is a deep-copy of dns.
1905 +func (dns *Msg) Copy() *Msg {
1906 + r1 := new(Msg)
1907 + r1.MsgHdr = dns.MsgHdr
1908 + r1.Compress = dns.Compress
1909 +
1910 + if len(dns.Question) > 0 {
1911 + r1.Question = make([]Question, len(dns.Question))
1912 + copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
1913 + }
1914 +
1915 + if len(dns.Answer) > 0 {
1916 + r1.Answer = make([]RR, len(dns.Answer))
1917 + for i := 0; i < len(dns.Answer); i++ {
1918 + r1.Answer[i] = dns.Answer[i].copy()
1919 + }
1920 + }
1921 +
1922 + if len(dns.Ns) > 0 {
1923 + r1.Ns = make([]RR, len(dns.Ns))
1924 + for i := 0; i < len(dns.Ns); i++ {
1925 + r1.Ns[i] = dns.Ns[i].copy()
1926 + }
1927 + }
1928 +
1929 + if len(dns.Extra) > 0 {
1930 + r1.Extra = make([]RR, len(dns.Extra))
1931 + for i := 0; i < len(dns.Extra); i++ {
1932 + r1.Extra[i] = dns.Extra[i].copy()
1933 + }
1934 + }
1935 +
1936 + return r1
1937 +}
Godeps/_workspace/src/github.com/miekg/dns/nsecx.go new
+110
@@ -0,0 +1,110 @@
1 +package dns
2 +
3 +import (
4 + "crypto/sha1"
5 + "hash"
6 + "io"
7 + "strings"
8 +)
9 +
10 +type saltWireFmt struct {
11 + Salt string `dns:"size-hex"`
12 +}
13 +
14 +// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in
15 +// uppercase.
16 +func HashName(label string, ha uint8, iter uint16, salt string) string {
17 + saltwire := new(saltWireFmt)
18 + saltwire.Salt = salt
19 + wire := make([]byte, DefaultMsgSize)
20 + n, err := PackStruct(saltwire, wire, 0)
21 + if err != nil {
22 + return ""
23 + }
24 + wire = wire[:n]
25 + name := make([]byte, 255)
26 + off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
27 + if err != nil {
28 + return ""
29 + }
30 + name = name[:off]
31 + var s hash.Hash
32 + switch ha {
33 + case SHA1:
34 + s = sha1.New()
35 + default:
36 + return ""
37 + }
38 +
39 + // k = 0
40 + name = append(name, wire...)
41 + io.WriteString(s, string(name))
42 + nsec3 := s.Sum(nil)
43 + // k > 0
44 + for k := uint16(0); k < iter; k++ {
45 + s.Reset()
46 + nsec3 = append(nsec3, wire...)
47 + io.WriteString(s, string(nsec3))
48 + nsec3 = s.Sum(nil)
49 + }
50 + return toBase32(nsec3)
51 +}
52 +
53 +type Denialer interface {
54 + // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
55 + Cover(name string) bool
56 + // Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3.
57 + Match(name string) bool
58 +}
59 +
60 +// Cover implements the Denialer interface.
61 +func (rr *NSEC) Cover(name string) bool {
62 + return true
63 +}
64 +
65 +// Match implements the Denialer interface.
66 +func (rr *NSEC) Match(name string) bool {
67 + return true
68 +}
69 +
70 +// Cover implements the Denialer interface.
71 +func (rr *NSEC3) Cover(name string) bool {
72 + // FIXME(miek): check if the zones match
73 + // FIXME(miek): check if we're not dealing with parent nsec3
74 + hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
75 + labels := Split(rr.Hdr.Name)
76 + if len(labels) < 2 {
77 + return false
78 + }
79 + hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot
80 + if hash == rr.NextDomain {
81 + return false // empty interval
82 + }
83 + if hash > rr.NextDomain { // last name, points to apex
84 + // hname > hash
85 + // hname > rr.NextDomain
86 + // TODO(miek)
87 + }
88 + if hname <= hash {
89 + return false
90 + }
91 + if hname >= rr.NextDomain {
92 + return false
93 + }
94 + return true
95 +}
96 +
97 +// Match implements the Denialer interface.
98 +func (rr *NSEC3) Match(name string) bool {
99 + // FIXME(miek): Check if we are in the same zone
100 + hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
101 + labels := Split(rr.Hdr.Name)
102 + if len(labels) < 2 {
103 + return false
104 + }
105 + hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the .
106 + if hash == hname {
107 + return true
108 + }
109 + return false
110 +}
Godeps/_workspace/src/github.com/miekg/dns/nsecx_test.go new
+33
@@ -0,0 +1,33 @@
1 +package dns
2 +
3 +import (
4 + "testing"
5 +)
6 +
7 +func TestPackNsec3(t *testing.T) {
8 + nsec3 := HashName("dnsex.nl.", SHA1, 0, "DEAD")
9 + if nsec3 != "ROCCJAE8BJJU7HN6T7NG3TNM8ACRS87J" {
10 + t.Logf("%v\n", nsec3)
11 + t.Fail()
12 + }
13 +
14 + nsec3 = HashName("a.b.c.example.org.", SHA1, 2, "DEAD")
15 + if nsec3 != "6LQ07OAHBTOOEU2R9ANI2AT70K5O0RCG" {
16 + t.Logf("%v\n", nsec3)
17 + t.Fail()
18 + }
19 +}
20 +
21 +func TestNsec3(t *testing.T) {
22 + // examples taken from .nl
23 + nsec3, _ := NewRR("39p91242oslggest5e6a7cci4iaeqvnk.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6 NS DS RRSIG")
24 + if !nsec3.(*NSEC3).Cover("snasajsksasasa.nl.") { // 39p94jrinub66hnpem8qdpstrec86pg3
25 + t.Logf("39p94jrinub66hnpem8qdpstrec86pg3. should be covered by 39p91242oslggest5e6a7cci4iaeqvnk.nl. - 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6")
26 + t.Fail()
27 + }
28 + nsec3, _ = NewRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
29 + if !nsec3.(*NSEC3).Match("nl.") { // sk4e8fj94u78smusb40o1n0oltbblu2r.nl.
30 + t.Logf("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
31 + t.Fail()
32 + }
33 +}
Godeps/_workspace/src/github.com/miekg/dns/parse_test.go new
+1409
@@ -0,0 +1,1409 @@
1 +package dns
2 +
3 +import (
4 + "bytes"
5 + "crypto/rsa"
6 + "encoding/hex"
7 + "fmt"
8 + "math/rand"
9 + "net"
10 + "reflect"
11 + "strconv"
12 + "strings"
13 + "testing"
14 + "testing/quick"
15 + "time"
16 +)
17 +
18 +func TestDotInName(t *testing.T) {
19 + buf := make([]byte, 20)
20 + PackDomainName("aa\\.bb.nl.", buf, 0, nil, false)
21 + // index 3 must be a real dot
22 + if buf[3] != '.' {
23 + t.Log("dot should be a real dot")
24 + t.Fail()
25 + }
26 +
27 + if buf[6] != 2 {
28 + t.Log("this must have the value 2")
29 + t.Fail()
30 + }
31 + dom, _, _ := UnpackDomainName(buf, 0)
32 + // printing it should yield the backspace again
33 + if dom != "aa\\.bb.nl." {
34 + t.Log("dot should have been escaped: " + dom)
35 + t.Fail()
36 + }
37 +}
38 +
39 +func TestDotLastInLabel(t *testing.T) {
40 + sample := "aa\\..au."
41 + buf := make([]byte, 20)
42 + _, err := PackDomainName(sample, buf, 0, nil, false)
43 + if err != nil {
44 + t.Fatalf("unexpected error packing domain: %s", err)
45 + }
46 + dom, _, _ := UnpackDomainName(buf, 0)
47 + if dom != sample {
48 + t.Fatalf("unpacked domain `%s' doesn't match packed domain", dom)
49 + }
50 +}
51 +
52 +func TestTooLongDomainName(t *testing.T) {
53 + l := "aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt."
54 + dom := l + l + l + l + l + l + l
55 + _, e := NewRR(dom + " IN A 127.0.0.1")
56 + if e == nil {
57 + t.Log("should be too long")
58 + t.Fail()
59 + } else {
60 + t.Logf("error is %s", e.Error())
61 + }
62 + _, e = NewRR("..com. IN A 127.0.0.1")
63 + if e == nil {
64 + t.Log("should fail")
65 + t.Fail()
66 + } else {
67 + t.Logf("error is %s", e.Error())
68 + }
69 +}
70 +
71 +func TestDomainName(t *testing.T) {
72 + tests := []string{"r\\.gieben.miek.nl.", "www\\.www.miek.nl.",
73 + "www.*.miek.nl.", "www.*.miek.nl.",
74 + }
75 + dbuff := make([]byte, 40)
76 +
77 + for _, ts := range tests {
78 + if _, err := PackDomainName(ts, dbuff, 0, nil, false); err != nil {
79 + t.Log("not a valid domain name")
80 + t.Fail()
81 + continue
82 + }
83 + n, _, err := UnpackDomainName(dbuff, 0)
84 + if err != nil {
85 + t.Log("failed to unpack packed domain name")
86 + t.Fail()
87 + continue
88 + }
89 + if ts != n {
90 + t.Logf("must be equal: in: %s, out: %s\n", ts, n)
91 + t.Fail()
92 + }
93 + }
94 +}
95 +
96 +func TestDomainNameAndTXTEscapes(t *testing.T) {
97 + tests := []byte{'.', '(', ')', ';', ' ', '@', '"', '\\', '\t', '\r', '\n', 0, 255}
98 + for _, b := range tests {
99 + rrbytes := []byte{
100 + 1, b, 0, // owner
101 + byte(TypeTXT >> 8), byte(TypeTXT),
102 + byte(ClassINET >> 8), byte(ClassINET),
103 + 0, 0, 0, 1, // TTL
104 + 0, 2, 1, b, // Data
105 + }
106 + rr1, _, err := UnpackRR(rrbytes, 0)
107 + if err != nil {
108 + panic(err)
109 + }
110 + s := rr1.String()
111 + rr2, err := NewRR(s)
112 + if err != nil {
113 + t.Logf("Error parsing unpacked RR's string: %v", err)
114 + t.Logf(" Bytes: %v\n", rrbytes)
115 + t.Logf("String: %v\n", s)
116 + t.Fail()
117 + }
118 + repacked := make([]byte, len(rrbytes))
119 + if _, err := PackRR(rr2, repacked, 0, nil, false); err != nil {
120 + t.Logf("error packing parsed RR: %v", err)
121 + t.Logf(" original Bytes: %v\n", rrbytes)
122 + t.Logf("unpacked Struct: %V\n", rr1)
123 + t.Logf(" parsed Struct: %V\n", rr2)
124 + t.Fail()
125 + }
126 + if !bytes.Equal(repacked, rrbytes) {
127 + t.Log("packed bytes don't match original bytes")
128 + t.Logf(" original bytes: %v", rrbytes)
129 + t.Logf(" packed bytes: %v", repacked)
130 + t.Logf("unpacked struct: %V", rr1)
131 + t.Logf(" parsed struct: %V", rr2)
132 + t.Fail()
133 + }
134 + }
135 +}
136 +
137 +func TestTXTEscapeParsing(t *testing.T) {
138 + test := [][]string{
139 + {`";"`, `";"`},
140 + {`\;`, `";"`},
141 + {`"\t"`, `"\t"`},
142 + {`"\r"`, `"\r"`},
143 + {`"\ "`, `" "`},
144 + {`"\;"`, `";"`},
145 + {`"\;\""`, `";\""`},
146 + {`"\(a\)"`, `"(a)"`},
147 + {`"\(a)"`, `"(a)"`},
148 + {`"(a\)"`, `"(a)"`},
149 + {`"(a)"`, `"(a)"`},
150 + {`"\048"`, `"0"`},
151 + {`"\` + "\n" + `"`, `"\n"`},
152 + {`"\` + "\r" + `"`, `"\r"`},
153 + {`"\` + "\x11" + `"`, `"\017"`},
154 + {`"\'"`, `"'"`},
155 + }
156 + for _, s := range test {
157 + rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0]))
158 + if err != nil {
159 + t.Errorf("Could not parse %v TXT: %s", s[0], err)
160 + continue
161 + }
162 +
163 + txt := sprintTxt(rr.(*TXT).Txt)
164 + if txt != s[1] {
165 + t.Errorf("Mismatch after parsing `%v` TXT record: `%v` != `%v`", s[0], txt, s[1])
166 + }
167 + }
168 +}
169 +
170 +func GenerateDomain(r *rand.Rand, size int) []byte {
171 + dnLen := size % 70 // artificially limit size so there's less to intrepret if a failure occurs
172 + var dn []byte
173 + done := false
174 + for i := 0; i < dnLen && !done; {
175 + max := dnLen - i
176 + if max > 63 {
177 + max = 63
178 + }
179 + lLen := max
180 + if lLen != 0 {
181 + lLen = int(r.Int31()) % max
182 + }
183 + done = lLen == 0
184 + if done {
185 + continue
186 + }
187 + l := make([]byte, lLen+1)
188 + l[0] = byte(lLen)
189 + for j := 0; j < lLen; j++ {
190 + l[j+1] = byte(rand.Int31())
191 + }
192 + dn = append(dn, l...)
193 + i += 1 + lLen
194 + }
195 + return append(dn, 0)
196 +}
197 +
198 +func TestDomainQuick(t *testing.T) {
199 + r := rand.New(rand.NewSource(0))
200 + f := func(l int) bool {
201 + db := GenerateDomain(r, l)
202 + ds, _, err := UnpackDomainName(db, 0)
203 + if err != nil {
204 + panic(err)
205 + }
206 + buf := make([]byte, 255)
207 + off, err := PackDomainName(ds, buf, 0, nil, false)
208 + if err != nil {
209 + t.Logf("error packing domain: %s", err.Error())
210 + t.Logf(" bytes: %v\n", db)
211 + t.Logf("string: %v\n", ds)
212 + return false
213 + }
214 + if !bytes.Equal(db, buf[:off]) {
215 + t.Logf("repacked domain doesn't match original:")
216 + t.Logf("src bytes: %v", db)
217 + t.Logf(" string: %v", ds)
218 + t.Logf("out bytes: %v", buf[:off])
219 + return false
220 + }
221 + return true
222 + }
223 + if err := quick.Check(f, nil); err != nil {
224 + t.Error(err)
225 + }
226 +}
227 +
228 +func GenerateTXT(r *rand.Rand, size int) []byte {
229 + rdLen := size % 300 // artificially limit size so there's less to intrepret if a failure occurs
230 + var rd []byte
231 + for i := 0; i < rdLen; {
232 + max := rdLen - 1
233 + if max > 255 {
234 + max = 255
235 + }
236 + sLen := max
237 + if max != 0 {
238 + sLen = int(r.Int31()) % max
239 + }
240 + s := make([]byte, sLen+1)
241 + s[0] = byte(sLen)
242 + for j := 0; j < sLen; j++ {
243 + s[j+1] = byte(rand.Int31())
244 + }
245 + rd = append(rd, s...)
246 + i += 1 + sLen
247 + }
248 + return rd
249 +}
250 +
251 +func TestTXTRRQuick(t *testing.T) {
252 + s := rand.NewSource(0)
253 + r := rand.New(s)
254 + typeAndClass := []byte{
255 + byte(TypeTXT >> 8), byte(TypeTXT),
256 + byte(ClassINET >> 8), byte(ClassINET),
257 + 0, 0, 0, 1, // TTL
258 + }
259 + f := func(l int) bool {
260 + owner := GenerateDomain(r, l)
261 + rdata := GenerateTXT(r, l)
262 + rrbytes := make([]byte, 0, len(owner)+2+2+4+2+len(rdata))
263 + rrbytes = append(rrbytes, owner...)
264 + rrbytes = append(rrbytes, typeAndClass...)
265 + rrbytes = append(rrbytes, byte(len(rdata)>>8))
266 + rrbytes = append(rrbytes, byte(len(rdata)))
267 + rrbytes = append(rrbytes, rdata...)
268 + rr, _, err := UnpackRR(rrbytes, 0)
269 + if err != nil {
270 + panic(err)
271 + }
272 + buf := make([]byte, len(rrbytes)*3)
273 + off, err := PackRR(rr, buf, 0, nil, false)
274 + if err != nil {
275 + t.Logf("pack Error: %s\nRR: %V", err.Error(), rr)
276 + return false
277 + }
278 + buf = buf[:off]
279 + if !bytes.Equal(buf, rrbytes) {
280 + t.Logf("packed bytes don't match original bytes")
281 + t.Logf("src bytes: %v", rrbytes)
282 + t.Logf(" struct: %V", rr)
283 + t.Logf("oUt bytes: %v", buf)
284 + return false
285 + }
286 + if len(rdata) == 0 {
287 + // string'ing won't produce any data to parse
288 + return true
289 + }
290 + rrString := rr.String()
291 + rr2, err := NewRR(rrString)
292 + if err != nil {
293 + t.Logf("error parsing own output: %s", err.Error())
294 + t.Logf("struct: %V", rr)
295 + t.Logf("string: %v", rrString)
296 + return false
297 + }
298 + if rr2.String() != rrString {
299 + t.Logf("parsed rr.String() doesn't match original string")
300 + t.Logf("original: %v", rrString)
301 + t.Logf(" parsed: %v", rr2.String())
302 + return false
303 + }
304 +
305 + buf = make([]byte, len(rrbytes)*3)
306 + off, err = PackRR(rr2, buf, 0, nil, false)
307 + if err != nil {
308 + t.Logf("error packing parsed rr: %s", err.Error())
309 + t.Logf("unpacked Struct: %V", rr)
310 + t.Logf(" string: %v", rrString)
311 + t.Logf(" parsed Struct: %V", rr2)
312 + return false
313 + }
314 + buf = buf[:off]
315 + if !bytes.Equal(buf, rrbytes) {
316 + t.Logf("parsed packed bytes don't match original bytes")
317 + t.Logf(" source bytes: %v", rrbytes)
318 + t.Logf("unpacked struct: %V", rr)
319 + t.Logf(" string: %v", rrString)
320 + t.Logf(" parsed struct: %V", rr2)
321 + t.Logf(" repacked bytes: %v", buf)
322 + return false
323 + }
324 + return true
325 + }
326 + c := &quick.Config{MaxCountScale: 10}
327 + if err := quick.Check(f, c); err != nil {
328 + t.Error(err)
329 + }
330 +}
331 +
332 +func TestParseDirectiveMisc(t *testing.T) {
333 + tests := map[string]string{
334 + "$ORIGIN miek.nl.\na IN NS b": "a.miek.nl.\t3600\tIN\tNS\tb.miek.nl.",
335 + "$TTL 2H\nmiek.nl. IN NS b.": "miek.nl.\t7200\tIN\tNS\tb.",
336 + "miek.nl. 1D IN NS b.": "miek.nl.\t86400\tIN\tNS\tb.",
337 + `name. IN SOA a6.nstld.com. hostmaster.nic.name. (
338 + 203362132 ; serial
339 + 5m ; refresh (5 minutes)
340 + 5m ; retry (5 minutes)
341 + 2w ; expire (2 weeks)
342 + 300 ; minimum (5 minutes)
343 +)`: "name.\t3600\tIN\tSOA\ta6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300",
344 + ". 3600000 IN NS ONE.MY-ROOTS.NET.": ".\t3600000\tIN\tNS\tONE.MY-ROOTS.NET.",
345 + "ONE.MY-ROOTS.NET. 3600000 IN A 192.168.1.1": "ONE.MY-ROOTS.NET.\t3600000\tIN\tA\t192.168.1.1",
346 + }
347 + for i, o := range tests {
348 + rr, e := NewRR(i)
349 + if e != nil {
350 + t.Log("failed to parse RR: " + e.Error())
351 + t.Fail()
352 + continue
353 + }
354 + if rr.String() != o {
355 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
356 + t.Fail()
357 + } else {
358 + t.Logf("RR is OK: `%s'", rr.String())
359 + }
360 + }
361 +}
362 +
363 +func TestNSEC(t *testing.T) {
364 + nsectests := map[string]string{
365 + "nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
366 + "p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM",
367 + "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC",
368 + "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
369 + "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSec Type65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
370 + }
371 + for i, o := range nsectests {
372 + rr, e := NewRR(i)
373 + if e != nil {
374 + t.Log("failed to parse RR: " + e.Error())
375 + t.Fail()
376 + continue
377 + }
378 + if rr.String() != o {
379 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
380 + t.Fail()
381 + } else {
382 + t.Logf("RR is OK: `%s'", rr.String())
383 + }
384 + }
385 +}
386 +
387 +func TestParseLOC(t *testing.T) {
388 + lt := map[string]string{
389 + "SW1A2AA.find.me.uk. LOC 51 30 12.748 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 30 12.748 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m",
390 + "SW1A2AA.find.me.uk. LOC 51 0 0.0 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 00 0.000 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m",
391 + }
392 + for i, o := range lt {
393 + rr, e := NewRR(i)
394 + if e != nil {
395 + t.Log("failed to parse RR: " + e.Error())
396 + t.Fail()
397 + continue
398 + }
399 + if rr.String() != o {
400 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
401 + t.Fail()
402 + } else {
403 + t.Logf("RR is OK: `%s'", rr.String())
404 + }
405 + }
406 +}
407 +
408 +func TestParseDS(t *testing.T) {
409 + dt := map[string]string{
410 + "example.net. 3600 IN DS 40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B 2071398F": "example.net.\t3600\tIN\tDS\t40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B2071398F",
411 + }
412 + for i, o := range dt {
413 + rr, e := NewRR(i)
414 + if e != nil {
415 + t.Log("failed to parse RR: " + e.Error())
416 + t.Fail()
417 + continue
418 + }
419 + if rr.String() != o {
420 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
421 + t.Fail()
422 + } else {
423 + t.Logf("RR is OK: `%s'", rr.String())
424 + }
425 + }
426 +}
427 +
428 +func TestQuotes(t *testing.T) {
429 + tests := map[string]string{
430 + `t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"",
431 + `t.example.com. IN TXT "a
432 + bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\n bc\"",
433 + `t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"",
434 + `t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"",
435 + `t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"",
436 + `t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
437 + `t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
438 + `t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
439 + `t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa \"",
440 + `t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa aaa\"",
441 + `t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa aaa\"",
442 + `t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
443 + "cid.urn.arpa. NAPTR 100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.",
444 + "cid.urn.arpa. NAPTR 100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.",
445 + "cid.urn.arpa. NAPTR 100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.",
446 + "cid.urn.arpa. NAPTR 100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .",
447 + }
448 + for i, o := range tests {
449 + rr, e := NewRR(i)
450 + if e != nil {
451 + t.Log("failed to parse RR: " + e.Error())
452 + t.Fail()
453 + continue
454 + }
455 + if rr.String() != o {
456 + t.Logf("`%s' should be equal to\n`%s', but is\n`%s'\n", i, o, rr.String())
457 + t.Fail()
458 + } else {
459 + t.Logf("RR is OK: `%s'", rr.String())
460 + }
461 + }
462 +}
463 +
464 +func TestParseClass(t *testing.T) {
465 + tests := map[string]string{
466 + "t.example.com. IN A 127.0.0.1": "t.example.com. 3600 IN A 127.0.0.1",
467 + "t.example.com. CS A 127.0.0.1": "t.example.com. 3600 CS A 127.0.0.1",
468 + "t.example.com. CH A 127.0.0.1": "t.example.com. 3600 CH A 127.0.0.1",
469 + // ClassANY can not occur in zone files
470 + // "t.example.com. ANY A 127.0.0.1": "t.example.com. 3600 ANY A 127.0.0.1",
471 + "t.example.com. NONE A 127.0.0.1": "t.example.com. 3600 NONE A 127.0.0.1",
472 + }
473 + for i, o := range tests {
474 + rr, e := NewRR(i)
475 + if e != nil {
476 + t.Log("failed to parse RR: " + e.Error())
477 + t.Fail()
478 + continue
479 + }
480 + if rr.String() != o {
481 + t.Logf("`%s' should be equal to\n`%s', but is\n`%s'\n", i, o, rr.String())
482 + t.Fail()
483 + } else {
484 + t.Logf("RR is OK: `%s'", rr.String())
485 + }
486 + }
487 +}
488 +
489 +func TestBrace(t *testing.T) {
490 + tests := map[string]string{
491 + "(miek.nl.) 3600 IN A 127.0.1.1": "miek.nl.\t3600\tIN\tA\t127.0.1.1",
492 + "miek.nl. (3600) IN MX (10) elektron.atoom.net.": "miek.nl.\t3600\tIN\tMX\t10 elektron.atoom.net.",
493 + `miek.nl. IN (
494 + 3600 A 127.0.0.1)`: "miek.nl.\t3600\tIN\tA\t127.0.0.1",
495 + "(miek.nl.) (A) (127.0.2.1)": "miek.nl.\t3600\tIN\tA\t127.0.2.1",
496 + "miek.nl A 127.0.3.1": "miek.nl.\t3600\tIN\tA\t127.0.3.1",
497 + "_ssh._tcp.local. 60 IN (PTR) stora._ssh._tcp.local.": "_ssh._tcp.local.\t60\tIN\tPTR\tstora._ssh._tcp.local.",
498 + "miek.nl. NS ns.miek.nl": "miek.nl.\t3600\tIN\tNS\tns.miek.nl.",
499 + `(miek.nl.) (
500 + (IN)
501 + (AAAA)
502 + (::1) )`: "miek.nl.\t3600\tIN\tAAAA\t::1",
503 + `(miek.nl.) (
504 + (IN)
505 + (AAAA)
506 + (::1))`: "miek.nl.\t3600\tIN\tAAAA\t::1",
507 + "miek.nl. IN AAAA ::2": "miek.nl.\t3600\tIN\tAAAA\t::2",
508 + `((m)(i)ek.(n)l.) (SOA) (soa.) (soa.) (
509 + 2009032802 ; serial
510 + 21600 ; refresh (6 hours)
511 + 7(2)00 ; retry (2 hours)
512 + 604()800 ; expire (1 week)
513 + 3600 ; minimum (1 hour)
514 + )`: "miek.nl.\t3600\tIN\tSOA\tsoa. soa. 2009032802 21600 7200 604800 3600",
515 + "miek\\.nl. IN A 127.0.0.10": "miek\\.nl.\t3600\tIN\tA\t127.0.0.10",
516 + "miek.nl. IN A 127.0.0.11": "miek.nl.\t3600\tIN\tA\t127.0.0.11",
517 + "miek.nl. A 127.0.0.12": "miek.nl.\t3600\tIN\tA\t127.0.0.12",
518 + `miek.nl. 86400 IN SOA elektron.atoom.net. miekg.atoom.net. (
519 + 2009032802 ; serial
520 + 21600 ; refresh (6 hours)
521 + 7200 ; retry (2 hours)
522 + 604800 ; expire (1 week)
523 + 3600 ; minimum (1 hour)
524 + )`: "miek.nl.\t86400\tIN\tSOA\telektron.atoom.net. miekg.atoom.net. 2009032802 21600 7200 604800 3600",
525 + }
526 + for i, o := range tests {
527 + rr, e := NewRR(i)
528 + if e != nil {
529 + t.Log("failed to parse RR: " + e.Error() + "\n\t" + i)
530 + t.Fail()
531 + continue
532 + }
533 + if rr.String() != o {
534 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
535 + t.Fail()
536 + } else {
537 + t.Logf("RR is OK: `%s'", rr.String())
538 + }
539 + }
540 +}
541 +
542 +func TestParseFailure(t *testing.T) {
543 + tests := []string{"miek.nl. IN A 327.0.0.1",
544 + "miek.nl. IN AAAA ::x",
545 + "miek.nl. IN MX a0 miek.nl.",
546 + "miek.nl aap IN MX mx.miek.nl.",
547 + "miek.nl 200 IN mxx 10 mx.miek.nl.",
548 + "miek.nl. inn MX 10 mx.miek.nl.",
549 + // "miek.nl. IN CNAME ", // actually valid nowadays, zero size rdata
550 + "miek.nl. IN CNAME ..",
551 + "miek.nl. PA MX 10 miek.nl.",
552 + "miek.nl. ) IN MX 10 miek.nl.",
553 + }
554 +
555 + for _, s := range tests {
556 + _, err := NewRR(s)
557 + if err == nil {
558 + t.Logf("should have triggered an error: \"%s\"", s)
559 + t.Fail()
560 + }
561 + }
562 +}
563 +
564 +func TestZoneParsing(t *testing.T) {
565 + // parse_test.db
566 + db := `
567 +a.example.com. IN A 127.0.0.1
568 +8db7._openpgpkey.example.com. IN OPENPGPKEY mQCNAzIG
569 +$ORIGIN a.example.com.
570 +test IN A 127.0.0.1
571 +$ORIGIN b.example.com.
572 +test IN CNAME test.a.example.com.
573 +`
574 + start := time.Now().UnixNano()
575 + to := ParseZone(strings.NewReader(db), "", "parse_test.db")
576 + var i int
577 + for x := range to {
578 + i++
579 + if x.Error != nil {
580 + t.Logf("%s\n", x.Error)
581 + t.Fail()
582 + continue
583 + }
584 + t.Logf("%s\n", x.RR)
585 + }
586 + delta := time.Now().UnixNano() - start
587 + t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9))
588 +}
589 +
590 +func ExampleZone() {
591 + zone := `$ORIGIN .
592 +$TTL 3600 ; 1 hour
593 +name IN SOA a6.nstld.com. hostmaster.nic.name. (
594 + 203362132 ; serial
595 + 300 ; refresh (5 minutes)
596 + 300 ; retry (5 minutes)
597 + 1209600 ; expire (2 weeks)
598 + 300 ; minimum (5 minutes)
599 + )
600 +$TTL 10800 ; 3 hours
601 +name. 10800 IN NS name.
602 + IN NS g6.nstld.com.
603 + 7200 NS h6.nstld.com.
604 + 3600 IN NS j6.nstld.com.
605 + IN 3600 NS k6.nstld.com.
606 + NS l6.nstld.com.
607 + NS a6.nstld.com.
608 + NS c6.nstld.com.
609 + NS d6.nstld.com.
610 + NS f6.nstld.com.
611 + NS m6.nstld.com.
612 +(
613 + NS m7.nstld.com.
614 +)
615 +$ORIGIN name.
616 +0-0onlus NS ns7.ehiweb.it.
617 + NS ns8.ehiweb.it.
618 +0-g MX 10 mx01.nic
619 + MX 10 mx02.nic
620 + MX 10 mx03.nic
621 + MX 10 mx04.nic
622 +$ORIGIN 0-g.name
623 +moutamassey NS ns01.yahoodomains.jp.
624 + NS ns02.yahoodomains.jp.
625 +`
626 + to := ParseZone(strings.NewReader(zone), "", "testzone")
627 + for x := range to {
628 + fmt.Printf("%s\n", x.RR)
629 + }
630 + // Output:
631 + // name. 3600 IN SOA a6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300
632 + // name. 10800 IN NS name.
633 + // name. 10800 IN NS g6.nstld.com.
634 + // name. 7200 IN NS h6.nstld.com.
635 + // name. 3600 IN NS j6.nstld.com.
636 + // name. 3600 IN NS k6.nstld.com.
637 + // name. 10800 IN NS l6.nstld.com.
638 + // name. 10800 IN NS a6.nstld.com.
639 + // name. 10800 IN NS c6.nstld.com.
640 + // name. 10800 IN NS d6.nstld.com.
641 + // name. 10800 IN NS f6.nstld.com.
642 + // name. 10800 IN NS m6.nstld.com.
643 + // name. 10800 IN NS m7.nstld.com.
644 + // 0-0onlus.name. 10800 IN NS ns7.ehiweb.it.
645 + // 0-0onlus.name. 10800 IN NS ns8.ehiweb.it.
646 + // 0-g.name. 10800 IN MX 10 mx01.nic.name.
647 + // 0-g.name. 10800 IN MX 10 mx02.nic.name.
648 + // 0-g.name. 10800 IN MX 10 mx03.nic.name.
649 + // 0-g.name. 10800 IN MX 10 mx04.nic.name.
650 + // moutamassey.0-g.name.name. 10800 IN NS ns01.yahoodomains.jp.
651 + // moutamassey.0-g.name.name. 10800 IN NS ns02.yahoodomains.jp.
652 +}
653 +
654 +func ExampleHIP() {
655 + h := `www.example.com IN HIP ( 2 200100107B1A74DF365639CC39F1D578
656 + AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p
657 +9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ
658 +b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
659 + rvs.example.com. )`
660 + if hip, err := NewRR(h); err == nil {
661 + fmt.Printf("%s\n", hip.String())
662 + }
663 + // Output:
664 + // www.example.com. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com.
665 +}
666 +
667 +func TestHIP(t *testing.T) {
668 + h := `www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578
669 + AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p
670 +9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ
671 +b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
672 + rvs1.example.com.
673 + rvs2.example.com. )`
674 + rr, err := NewRR(h)
675 + if err != nil {
676 + t.Fatalf("failed to parse RR: %s", err)
677 + }
678 + t.Logf("RR: %s", rr)
679 + msg := new(Msg)
680 + msg.Answer = []RR{rr, rr}
681 + bytes, err := msg.Pack()
682 + if err != nil {
683 + t.Fatalf("failed to pack msg: %s", err)
684 + }
685 + if err := msg.Unpack(bytes); err != nil {
686 + t.Fatalf("failed to unpack msg: %s", err)
687 + }
688 + if len(msg.Answer) != 2 {
689 + t.Fatalf("2 answers expected: %V", msg)
690 + }
691 + for i, rr := range msg.Answer {
692 + rr := rr.(*HIP)
693 + t.Logf("RR: %s", rr)
694 + if l := len(rr.RendezvousServers); l != 2 {
695 + t.Fatalf("2 servers expected, only %d in record %d:\n%V", l, i, msg)
696 + }
697 + for j, s := range []string{"rvs1.example.com.", "rvs2.example.com."} {
698 + if rr.RendezvousServers[j] != s {
699 + t.Fatalf("expected server %d of record %d to be %s:\n%V", j, i, s, msg)
700 + }
701 + }
702 + }
703 +}
704 +
705 +func ExampleSOA() {
706 + s := "example.com. 1000 SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100"
707 + if soa, err := NewRR(s); err == nil {
708 + fmt.Printf("%s\n", soa.String())
709 + }
710 + // Output:
711 + // example.com. 1000 IN SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100
712 +}
713 +
714 +func TestLineNumberError(t *testing.T) {
715 + s := "example.com. 1000 SOA master.example.com. admin.example.com. monkey 4294967294 4294967293 4294967295 100"
716 + if _, err := NewRR(s); err != nil {
717 + if err.Error() != "dns: bad SOA zone parameter: \"monkey\" at line: 1:68" {
718 + t.Logf("not expecting this error: " + err.Error())
719 + t.Fail()
720 + }
721 + }
722 +}
723 +
724 +// Test with no known RR on the line
725 +func TestLineNumberError2(t *testing.T) {
726 + tests := map[string]string{
727 + "example.com. 1000 SO master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100": "dns: expecting RR type or class, not this...: \"SO\" at line: 1:21",
728 + "example.com 1000 IN TALINK a.example.com. b..example.com.": "dns: bad TALINK NextName: \"b..example.com.\" at line: 1:57",
729 + "example.com 1000 IN TALINK ( a.example.com. b..example.com. )": "dns: bad TALINK NextName: \"b..example.com.\" at line: 1:60",
730 + `example.com 1000 IN TALINK ( a.example.com.
731 + bb..example.com. )`: "dns: bad TALINK NextName: \"bb..example.com.\" at line: 2:18",
732 + // This is a bug, it should report an error on line 1, but the new is already processed.
733 + `example.com 1000 IN TALINK ( a.example.com. b...example.com.
734 + )`: "dns: bad TALINK NextName: \"b...example.com.\" at line: 2:1"}
735 +
736 + for in, err := range tests {
737 + _, e := NewRR(in)
738 + if e == nil {
739 + t.Fail()
740 + } else {
741 + if e.Error() != err {
742 + t.Logf("%s\n", in)
743 + t.Logf("error should be %s is %s\n", err, e.Error())
744 + t.Fail()
745 + }
746 + }
747 + }
748 +}
749 +
750 +// Test if the calculations are correct
751 +func TestRfc1982(t *testing.T) {
752 + // If the current time and the timestamp are more than 68 years apart
753 + // it means the date has wrapped. 0 is 1970
754 +
755 + // fall in the current 68 year span
756 + strtests := []string{"20120525134203", "19700101000000", "20380119031408"}
757 + for _, v := range strtests {
758 + if x, _ := StringToTime(v); v != TimeToString(x) {
759 + t.Logf("1982 arithmetic string failure %s (%s:%d)", v, TimeToString(x), x)
760 + t.Fail()
761 + }
762 + }
763 +
764 + inttests := map[uint32]string{0: "19700101000000",
765 + 1 << 31: "20380119031408",
766 + 1<<32 - 1: "21060207062815",
767 + }
768 + for i, v := range inttests {
769 + if TimeToString(i) != v {
770 + t.Logf("1982 arithmetic int failure %d:%s (%s)", i, v, TimeToString(i))
771 + t.Fail()
772 + }
773 + }
774 +
775 + // Future tests, these dates get parsed to a date within the current 136 year span
776 + future := map[string]string{"22680119031408": "20631123173144",
777 + "19010101121212": "20370206184028",
778 + "19210101121212": "20570206184028",
779 + "19500101121212": "20860206184028",
780 + "19700101000000": "19700101000000",
781 + "19690101000000": "21050207062816",
782 + "29210101121212": "21040522212236",
783 + }
784 + for from, to := range future {
785 + x, _ := StringToTime(from)
786 + y := TimeToString(x)
787 + if y != to {
788 + t.Logf("1982 arithmetic future failure %s:%s (%s)", from, to, y)
789 + t.Fail()
790 + }
791 + }
792 +}
793 +
794 +func TestEmpty(t *testing.T) {
795 + for _ = range ParseZone(strings.NewReader(""), "", "") {
796 + t.Logf("should be empty")
797 + t.Fail()
798 + }
799 +}
800 +
801 +func TestLowercaseTokens(t *testing.T) {
802 + var testrecords = []string{
803 + "example.org. 300 IN a 1.2.3.4",
804 + "example.org. 300 in A 1.2.3.4",
805 + "example.org. 300 in a 1.2.3.4",
806 + "example.org. 300 a 1.2.3.4",
807 + "example.org. 300 A 1.2.3.4",
808 + "example.org. IN a 1.2.3.4",
809 + "example.org. in A 1.2.3.4",
810 + "example.org. in a 1.2.3.4",
811 + "example.org. a 1.2.3.4",
812 + "example.org. A 1.2.3.4",
813 + "example.org. a 1.2.3.4",
814 + "$ORIGIN example.org.\n a 1.2.3.4",
815 + "$Origin example.org.\n a 1.2.3.4",
816 + "$origin example.org.\n a 1.2.3.4",
817 + "example.org. Class1 Type1 1.2.3.4",
818 + }
819 + for _, testrr := range testrecords {
820 + _, err := NewRR(testrr)
821 + if err != nil {
822 + t.Errorf("failed to parse %#v, got %s", testrr, err.Error())
823 + }
824 + }
825 +}
826 +
827 +func ExampleGenerate() {
828 + // From the manual: http://www.bind9.net/manual/bind/9.3.2/Bv9ARM.ch06.html#id2566761
829 + zone := "$GENERATE 1-2 0 NS SERVER$.EXAMPLE.\n$GENERATE 1-8 $ CNAME $.0"
830 + to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "")
831 + for x := range to {
832 + if x.Error == nil {
833 + fmt.Printf("%s\n", x.RR.String())
834 + }
835 + }
836 + // Output:
837 + // 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER1.EXAMPLE.
838 + // 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER2.EXAMPLE.
839 + // 1.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 1.0.0.0.192.IN-ADDR.ARPA.
840 + // 2.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 2.0.0.0.192.IN-ADDR.ARPA.
841 + // 3.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 3.0.0.0.192.IN-ADDR.ARPA.
842 + // 4.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 4.0.0.0.192.IN-ADDR.ARPA.
843 + // 5.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 5.0.0.0.192.IN-ADDR.ARPA.
844 + // 6.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 6.0.0.0.192.IN-ADDR.ARPA.
845 + // 7.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 7.0.0.0.192.IN-ADDR.ARPA.
846 + // 8.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 8.0.0.0.192.IN-ADDR.ARPA.
847 +}
848 +
849 +func TestSRVPacking(t *testing.T) {
850 + msg := Msg{}
851 +
852 + things := []string{"1.2.3.4:8484",
853 + "45.45.45.45:8484",
854 + "84.84.84.84:8484",
855 + }
856 +
857 + for i, n := range things {
858 + h, p, err := net.SplitHostPort(n)
859 + if err != nil {
860 + continue
861 + }
862 + port := 8484
863 + tmp, err := strconv.Atoi(p)
864 + if err == nil {
865 + port = tmp
866 + }
867 +
868 + rr := &SRV{
869 + Hdr: RR_Header{Name: "somename.",
870 + Rrtype: TypeSRV,
871 + Class: ClassINET,
872 + Ttl: 5},
873 + Priority: uint16(i),
874 + Weight: 5,
875 + Port: uint16(port),
876 + Target: h + ".",
877 + }
878 +
879 + msg.Answer = append(msg.Answer, rr)
880 + }
881 +
882 + _, err := msg.Pack()
883 + if err != nil {
884 + t.Fatalf("couldn't pack %v\n", msg)
885 + }
886 +}
887 +
888 +func TestParseBackslash(t *testing.T) {
889 + if r, e := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); e != nil {
890 + t.Fatalf("could not create RR with \\000 in it")
891 + } else {
892 + t.Logf("parsed %s\n", r.String())
893 + }
894 + if r, e := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); e != nil {
895 + t.Fatalf("could not create RR with \\000 in it")
896 + } else {
897 + t.Logf("parsed %s\n", r.String())
898 + }
899 + if r, e := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); e != nil {
900 + t.Fatalf("could not create RR with \\ and \\@ in it")
901 + } else {
902 + t.Logf("parsed %s\n", r.String())
903 + }
904 +}
905 +
906 +func TestILNP(t *testing.T) {
907 + tests := []string{
908 + "host1.example.com.\t3600\tIN\tNID\t10 0014:4fff:ff20:ee64",
909 + "host1.example.com.\t3600\tIN\tNID\t20 0015:5fff:ff21:ee65",
910 + "host2.example.com.\t3600\tIN\tNID\t10 0016:6fff:ff22:ee66",
911 + "host1.example.com.\t3600\tIN\tL32\t10 10.1.2.0",
912 + "host1.example.com.\t3600\tIN\tL32\t20 10.1.4.0",
913 + "host2.example.com.\t3600\tIN\tL32\t10 10.1.8.0",
914 + "host1.example.com.\t3600\tIN\tL64\t10 2001:0DB8:1140:1000",
915 + "host1.example.com.\t3600\tIN\tL64\t20 2001:0DB8:2140:2000",
916 + "host2.example.com.\t3600\tIN\tL64\t10 2001:0DB8:4140:4000",
917 + "host1.example.com.\t3600\tIN\tLP\t10 l64-subnet1.example.com.",
918 + "host1.example.com.\t3600\tIN\tLP\t10 l64-subnet2.example.com.",
919 + "host1.example.com.\t3600\tIN\tLP\t20 l32-subnet1.example.com.",
920 + }
921 + for _, t1 := range tests {
922 + r, e := NewRR(t1)
923 + if e != nil {
924 + t.Fatalf("an error occured: %s\n", e.Error())
925 + } else {
926 + if t1 != r.String() {
927 + t.Fatalf("strings should be equal %s %s", t1, r.String())
928 + }
929 + }
930 + }
931 +}
932 +
933 +func TestNsapGposEidNimloc(t *testing.T) {
934 + dt := map[string]string{
935 + "foo.bar.com. IN NSAP 21 47000580ffff000000321099991111222233334444": "foo.bar.com.\t3600\tIN\tNSAP\t21 47000580ffff000000321099991111222233334444",
936 + "host.school.de IN NSAP 17 39276f3100111100002222333344449876": "host.school.de.\t3600\tIN\tNSAP\t17 39276f3100111100002222333344449876",
937 + "444433332222111199990123000000ff. NSAP-PTR foo.bar.com.": "444433332222111199990123000000ff.\t3600\tIN\tNSAP-PTR\tfoo.bar.com.",
938 + "lillee. IN GPOS -32.6882 116.8652 10.0": "lillee.\t3600\tIN\tGPOS\t-32.6882 116.8652 10.0",
939 + "hinault. IN GPOS -22.6882 116.8652 250.0": "hinault.\t3600\tIN\tGPOS\t-22.6882 116.8652 250.0",
940 + "VENERA. IN NIMLOC 75234159EAC457800920": "VENERA.\t3600\tIN\tNIMLOC\t75234159EAC457800920",
941 + "VAXA. IN EID 3141592653589793": "VAXA.\t3600\tIN\tEID\t3141592653589793",
942 + }
943 + for i, o := range dt {
944 + rr, e := NewRR(i)
945 + if e != nil {
946 + t.Log("failed to parse RR: " + e.Error())
947 + t.Fail()
948 + continue
949 + }
950 + if rr.String() != o {
951 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
952 + t.Fail()
953 + } else {
954 + t.Logf("RR is OK: `%s'", rr.String())
955 + }
956 + }
957 +}
958 +
959 +func TestPX(t *testing.T) {
960 + dt := map[string]string{
961 + "*.net2.it. IN PX 10 net2.it. PRMD-net2.ADMD-p400.C-it.": "*.net2.it.\t3600\tIN\tPX\t10 net2.it. PRMD-net2.ADMD-p400.C-it.",
962 + "ab.net2.it. IN PX 10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.": "ab.net2.it.\t3600\tIN\tPX\t10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.",
963 + }
964 + for i, o := range dt {
965 + rr, e := NewRR(i)
966 + if e != nil {
967 + t.Log("failed to parse RR: " + e.Error())
968 + t.Fail()
969 + continue
970 + }
971 + if rr.String() != o {
972 + t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String())
973 + t.Fail()
974 + } else {
975 + t.Logf("RR is OK: `%s'", rr.String())
976 + }
977 + }
978 +}
979 +
980 +func TestComment(t *testing.T) {
981 + // Comments we must see
982 + comments := map[string]bool{"; this is comment 1": true,
983 + "; this is comment 4": true, "; this is comment 6": true,
984 + "; this is comment 7": true, "; this is comment 8": true}
985 + zone := `
986 +foo. IN A 10.0.0.1 ; this is comment 1
987 +foo. IN A (
988 + 10.0.0.2 ; this is comment2
989 +)
990 +; this is comment3
991 +foo. IN A 10.0.0.3
992 +foo. IN A ( 10.0.0.4 ); this is comment 4
993 +
994 +foo. IN A 10.0.0.5
995 +; this is comment5
996 +
997 +foo. IN A 10.0.0.6
998 +
999 +foo. IN DNSKEY 256 3 5 AwEAAb+8l ; this is comment 6
1000 +foo. IN NSEC miek.nl. TXT RRSIG NSEC; this is comment 7
1001 +foo. IN TXT "THIS IS TEXT MAN"; this is comment 8
1002 +`
1003 + for x := range ParseZone(strings.NewReader(zone), ".", "") {
1004 + if x.Error == nil {
1005 + if x.Comment != "" {
1006 + if _, ok := comments[x.Comment]; !ok {
1007 + t.Logf("wrong comment %s", x.Comment)
1008 + t.Fail()
1009 + }
1010 + }
1011 + }
1012 + }
1013 +}
1014 +
1015 +func TestEUIxx(t *testing.T) {
1016 + tests := map[string]string{
1017 + "host.example. IN EUI48 00-00-5e-90-01-2a": "host.example.\t3600\tIN\tEUI48\t00-00-5e-90-01-2a",
1018 + "host.example. IN EUI64 00-00-5e-ef-00-00-00-2a": "host.example.\t3600\tIN\tEUI64\t00-00-5e-ef-00-00-00-2a",
1019 + }
1020 + for i, o := range tests {
1021 + r, e := NewRR(i)
1022 + if e != nil {
1023 + t.Logf("failed to parse %s: %s\n", i, e.Error())
1024 + t.Fail()
1025 + }
1026 + if r.String() != o {
1027 + t.Logf("want %s, got %s\n", o, r.String())
1028 + t.Fail()
1029 + }
1030 + }
1031 +}
1032 +
1033 +func TestUserRR(t *testing.T) {
1034 + tests := map[string]string{
1035 + "host.example. IN UID 1234": "host.example.\t3600\tIN\tUID\t1234",
1036 + "host.example. IN GID 1234556": "host.example.\t3600\tIN\tGID\t1234556",
1037 + "host.example. IN UINFO \"Miek Gieben\"": "host.example.\t3600\tIN\tUINFO\t\"Miek Gieben\"",
1038 + }
1039 + for i, o := range tests {
1040 + r, e := NewRR(i)
1041 + if e != nil {
1042 + t.Logf("failed to parse %s: %s\n", i, e.Error())
1043 + t.Fail()
1044 + }
1045 + if r.String() != o {
1046 + t.Logf("want %s, got %s\n", o, r.String())
1047 + t.Fail()
1048 + }
1049 + }
1050 +}
1051 +
1052 +func TestTXT(t *testing.T) {
1053 + // Test single entry TXT record
1054 + rr, err := NewRR(`_raop._tcp.local. 60 IN TXT "single value"`)
1055 + if err != nil {
1056 + t.Error("failed to parse single value TXT record", err)
1057 + } else if rr, ok := rr.(*TXT); !ok {
1058 + t.Error("wrong type, record should be of type TXT")
1059 + } else {
1060 + if len(rr.Txt) != 1 {
1061 + t.Error("bad size of TXT value:", len(rr.Txt))
1062 + } else if rr.Txt[0] != "single value" {
1063 + t.Error("bad single value")
1064 + }
1065 + if rr.String() != `_raop._tcp.local. 60 IN TXT "single value"` {
1066 + t.Error("bad representation of TXT record:", rr.String())
1067 + }
1068 + if rr.len() != 28+1+12 {
1069 + t.Error("bad size of serialized record:", rr.len())
1070 + }
1071 + }
1072 +
1073 + // Test multi entries TXT record
1074 + rr, err = NewRR(`_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"`)
1075 + if err != nil {
1076 + t.Error("failed to parse multi-values TXT record", err)
1077 + } else if rr, ok := rr.(*TXT); !ok {
1078 + t.Error("wrong type, record should be of type TXT")
1079 + } else {
1080 + if len(rr.Txt) != 4 {
1081 + t.Error("bad size of TXT multi-value:", len(rr.Txt))
1082 + } else if rr.Txt[0] != "a=1" || rr.Txt[1] != "b=2" || rr.Txt[2] != "c=3" || rr.Txt[3] != "d=4" {
1083 + t.Error("bad values in TXT records")
1084 + }
1085 + if rr.String() != `_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"` {
1086 + t.Error("bad representation of TXT multi value record:", rr.String())
1087 + }
1088 + if rr.len() != 28+1+3+1+3+1+3+1+3 {
1089 + t.Error("bad size of serialized multi value record:", rr.len())
1090 + }
1091 + }
1092 +
1093 + // Test empty-string in TXT record
1094 + rr, err = NewRR(`_raop._tcp.local. 60 IN TXT ""`)
1095 + if err != nil {
1096 + t.Error("failed to parse empty-string TXT record", err)
1097 + } else if rr, ok := rr.(*TXT); !ok {
1098 + t.Error("wrong type, record should be of type TXT")
1099 + } else {
1100 + if len(rr.Txt) != 1 {
1101 + t.Error("bad size of TXT empty-string value:", len(rr.Txt))
1102 + } else if rr.Txt[0] != "" {
1103 + t.Error("bad value for empty-string TXT record")
1104 + }
1105 + if rr.String() != `_raop._tcp.local. 60 IN TXT ""` {
1106 + t.Error("bad representation of empty-string TXT record:", rr.String())
1107 + }
1108 + if rr.len() != 28+1 {
1109 + t.Error("bad size of serialized record:", rr.len())
1110 + }
1111 + }
1112 +}
1113 +
1114 +func TestTypeXXXX(t *testing.T) {
1115 + _, err := NewRR("example.com IN TYPE1234 \\# 4 aabbccdd")
1116 + if err != nil {
1117 + t.Logf("failed to parse TYPE1234 RR: %s", err.Error())
1118 + t.Fail()
1119 + }
1120 + _, err = NewRR("example.com IN TYPE655341 \\# 8 aabbccddaabbccdd")
1121 + if err == nil {
1122 + t.Logf("this should not work, for TYPE655341")
1123 + t.Fail()
1124 + }
1125 + _, err = NewRR("example.com IN TYPE1 \\# 4 0a000001")
1126 + if err == nil {
1127 + t.Logf("this should not work")
1128 + t.Fail()
1129 + }
1130 +}
1131 +
1132 +func TestPTR(t *testing.T) {
1133 + _, err := NewRR("144.2.0.192.in-addr.arpa. 900 IN PTR ilouse03146p0\\(.example.com.")
1134 + if err != nil {
1135 + t.Error("failed to parse ", err.Error())
1136 + }
1137 +}
1138 +
1139 +func TestDigit(t *testing.T) {
1140 + tests := map[string]byte{
1141 + "miek\\000.nl. 100 IN TXT \"A\"": 0,
1142 + "miek\\001.nl. 100 IN TXT \"A\"": 1,
1143 + "miek\\254.nl. 100 IN TXT \"A\"": 254,
1144 + "miek\\255.nl. 100 IN TXT \"A\"": 255,
1145 + "miek\\256.nl. 100 IN TXT \"A\"": 0,
1146 + "miek\\257.nl. 100 IN TXT \"A\"": 1,
1147 + "miek\\004.nl. 100 IN TXT \"A\"": 4,
1148 + }
1149 + for s, i := range tests {
1150 + r, e := NewRR(s)
1151 + buf := make([]byte, 40)
1152 + if e != nil {
1153 + t.Fatalf("failed to parse %s\n", e.Error())
1154 + }
1155 + PackRR(r, buf, 0, nil, false)
1156 + t.Logf("%v\n", buf)
1157 + if buf[5] != i {
1158 + t.Fatalf("5 pos must be %d, is %d", i, buf[5])
1159 + }
1160 + r1, _, _ := UnpackRR(buf, 0)
1161 + if r1.Header().Ttl != 100 {
1162 + t.Fatalf("TTL should %d, is %d", 100, r1.Header().Ttl)
1163 + }
1164 + }
1165 +}
1166 +
1167 +func TestParseRRSIGTimestamp(t *testing.T) {
1168 + tests := map[string]bool{
1169 + `miek.nl. IN RRSIG SOA 8 2 43200 20140210031301 20140111031301 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true,
1170 + `miek.nl. IN RRSIG SOA 8 2 43200 315565800 4102477800 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true,
1171 + }
1172 + for r, _ := range tests {
1173 + _, e := NewRR(r)
1174 + if e != nil {
1175 + t.Fail()
1176 + t.Logf("%s\n", e.Error())
1177 + }
1178 + }
1179 +}
1180 +
1181 +func TestTxtEqual(t *testing.T) {
1182 + rr1 := new(TXT)
1183 + rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
1184 + rr1.Txt = []string{"a\"a", "\"", "b"}
1185 + rr2, _ := NewRR(rr1.String())
1186 + if rr1.String() != rr2.String() {
1187 + t.Logf("these two TXT records should match")
1188 + t.Logf("\n%s\n%s\n", rr1.String(), rr2.String())
1189 + t.Fail() // This is not an error, but keep this test.
1190 + }
1191 + t.Logf("\n%s\n%s\n", rr1.String(), rr2.String())
1192 +}
1193 +
1194 +func TestTxtLong(t *testing.T) {
1195 + rr1 := new(TXT)
1196 + rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
1197 + // Make a long txt record, this breaks when sending the packet,
1198 + // but not earlier.
1199 + rr1.Txt = []string{"start-"}
1200 + for i := 0; i < 200; i++ {
1201 + rr1.Txt[0] += "start-"
1202 + }
1203 + str := rr1.String()
1204 + if len(str) < len(rr1.Txt[0]) {
1205 + t.Logf("string conversion should work")
1206 + t.Fail()
1207 + }
1208 +}
1209 +
1210 +// Basically, don't crash.
1211 +func TestMalformedPackets(t *testing.T) {
1212 + var packets = []string{
1213 + "0021641c0000000100000000000078787878787878787878787303636f6d0000100001",
1214 + }
1215 +
1216 + // com = 63 6f 6d
1217 + for _, packet := range packets {
1218 + data, _ := hex.DecodeString(packet)
1219 + // for _, v := range data {
1220 + // t.Logf("%s ", string(v))
1221 + // }
1222 + var msg Msg
1223 + msg.Unpack(data)
1224 + // println(msg.String())
1225 + }
1226 +}
1227 +
1228 +type algorithm struct {
1229 + name uint8
1230 + bits int
1231 +}
1232 +
1233 +func TestNewPrivateKey(t *testing.T) {
1234 + if testing.Short() {
1235 + t.Skip("skipping test in short mode.")
1236 + }
1237 + algorithms := []algorithm{
1238 + algorithm{ECDSAP256SHA256, 256},
1239 + algorithm{ECDSAP384SHA384, 384},
1240 + algorithm{RSASHA1, 1024},
1241 + algorithm{RSASHA256, 2048},
1242 + algorithm{DSA, 1024},
1243 + }
1244 +
1245 + for _, algo := range algorithms {
1246 + key := new(DNSKEY)
1247 + key.Hdr.Rrtype = TypeDNSKEY
1248 + key.Hdr.Name = "miek.nl."
1249 + key.Hdr.Class = ClassINET
1250 + key.Hdr.Ttl = 14400
1251 + key.Flags = 256
1252 + key.Protocol = 3
1253 + key.Algorithm = algo.name
1254 + privkey, err := key.Generate(algo.bits)
1255 + if err != nil {
1256 + t.Fatal(err.Error())
1257 + }
1258 +
1259 + newPrivKey, err := key.NewPrivateKey(key.PrivateKeyString(privkey))
1260 + if err != nil {
1261 + t.Log(key.String())
1262 + t.Log(key.PrivateKeyString(privkey))
1263 +
1264 + t.Fatal(err.Error())
1265 + }
1266 +
1267 + switch newPrivKey := newPrivKey.(type) {
1268 + case *RSAPrivateKey:
1269 + (*rsa.PrivateKey)(newPrivKey).Precompute()
1270 + }
1271 +
1272 + if !reflect.DeepEqual(privkey, newPrivKey) {
1273 + t.Errorf("[%v] Private keys differ:\n%#v\n%#v\n", AlgorithmToString[algo.name], privkey, newPrivKey)
1274 + }
1275 + }
1276 +}
1277 +
1278 +// special input test
1279 +func TestNewRRSpecial(t *testing.T) {
1280 + var (
1281 + rr RR
1282 + err error
1283 + expect string
1284 + )
1285 +
1286 + rr, err = NewRR("; comment")
1287 + expect = ""
1288 + if err != nil {
1289 + t.Errorf("unexpected err: %s", err)
1290 + }
1291 + if rr != nil {
1292 + t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
1293 + }
1294 +
1295 + rr, err = NewRR("")
1296 + expect = ""
1297 + if err != nil {
1298 + t.Errorf("unexpected err: %s", err)
1299 + }
1300 + if rr != nil {
1301 + t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
1302 + }
1303 +
1304 + rr, err = NewRR("$ORIGIN foo.")
1305 + expect = ""
1306 + if err != nil {
1307 + t.Errorf("unexpected err: %s", err)
1308 + }
1309 + if rr != nil {
1310 + t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
1311 + }
1312 +
1313 + rr, err = NewRR(" ")
1314 + expect = ""
1315 + if err != nil {
1316 + t.Errorf("unexpected err: %s", err)
1317 + }
1318 + if rr != nil {
1319 + t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
1320 + }
1321 +
1322 + rr, err = NewRR("\n")
1323 + expect = ""
1324 + if err != nil {
1325 + t.Errorf("unexpected err: %s", err)
1326 + }
1327 + if rr != nil {
1328 + t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
1329 + }
1330 +
1331 + rr, err = NewRR("foo. A 1.1.1.1\nbar. A 2.2.2.2")
1332 + expect = "foo.\t3600\tIN\tA\t1.1.1.1"
1333 + if err != nil {
1334 + t.Errorf("unexpected err: %s", err)
1335 + }
1336 + if rr == nil || rr.String() != expect {
1337 + t.Errorf("unexpected result: [%s] != [%s]", rr, expect)
1338 + }
1339 +}
1340 +
1341 +func TestPrintfVerbsRdata(t *testing.T) {
1342 + x, _ := NewRR("www.miek.nl. IN MX 20 mx.miek.nl.")
1343 + if Field(x, 1) != "20" {
1344 + t.Errorf("should be 20")
1345 + }
1346 + if Field(x, 2) != "mx.miek.nl." {
1347 + t.Errorf("should be mx.miek.nl.")
1348 + }
1349 +
1350 + x, _ = NewRR("www.miek.nl. IN A 127.0.0.1")
1351 + if Field(x, 1) != "127.0.0.1" {
1352 + t.Errorf("should be 127.0.0.1")
1353 + }
1354 +
1355 + x, _ = NewRR("www.miek.nl. IN AAAA ::1")
1356 + if Field(x, 1) != "::1" {
1357 + t.Errorf("should be ::1")
1358 + }
1359 +
1360 + x, _ = NewRR("www.miek.nl. IN NSEC a.miek.nl. A NS SOA MX AAAA")
1361 + if Field(x, 1) != "a.miek.nl." {
1362 + t.Errorf("should be a.miek.nl.")
1363 + }
1364 + if Field(x, 2) != "A NS SOA MX AAAA" {
1365 + t.Errorf("should be A NS SOA MX AAAA")
1366 + }
1367 +
1368 + x, _ = NewRR("www.miek.nl. IN TXT \"first\" \"second\"")
1369 + if Field(x, 1) != "first second" {
1370 + t.Errorf("should be first second")
1371 + }
1372 + if Field(x, 0) != "" {
1373 + t.Errorf("should be empty")
1374 + }
1375 +}
1376 +
1377 +func TestParseIPSECKEY(t *testing.T) {
1378 + tests := []string{
1379 + "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
1380 + "38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
1381 +
1382 + "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
1383 + "38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
1384 +
1385 + "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
1386 + "38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
1387 +
1388 + "38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
1389 + "38.1.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
1390 +
1391 + "0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
1392 + "0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0.\t7200\tIN\tIPSECKEY\t10 2 2 2001:db8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
1393 + }
1394 + for i := 0; i < len(tests)-1; i++ {
1395 + t1 := tests[i]
1396 + e1 := tests[i+1]
1397 + r, e := NewRR(t1)
1398 + if e != nil {
1399 + t.Logf("failed to parse IPSECKEY %s", e)
1400 + continue
1401 + }
1402 + if r.String() != e1 {
1403 + t.Logf("these two IPSECKEY records should match")
1404 + t.Logf("\n%s\n%s\n", r.String(), e1)
1405 + t.Fail()
1406 + }
1407 + i++
1408 + }
1409 +}
Godeps/_workspace/src/github.com/miekg/dns/privaterr.go new
+122
@@ -0,0 +1,122 @@
1 +/*
2 +PRIVATE RR
3 +
4 +RFC 6895 sets aside a range of type codes for private use. This range
5 +is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
6 +can be used, before requesting an official type code from IANA.
7 +*/
8 +package dns
9 +
10 +import (
11 + "fmt"
12 + "strings"
13 +)
14 +
15 +// PrivateRdata is an interface used for implementing "Private Use" RR types, see
16 +// RFC 6895. This allows one to experiment with new RR types, without requesting an
17 +// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove.
18 +type PrivateRdata interface {
19 + // String returns the text presentaton of the Rdata of the Private RR.
20 + String() string
21 + // Parse parses the Rdata of the private RR.
22 + Parse([]string) error
23 + // Pack is used when packing a private RR into a buffer.
24 + Pack([]byte) (int, error)
25 + // Unpack is used when unpacking a private RR from a buffer.
26 + // TODO(miek): diff. signature than Pack, see edns0.go for instance.
27 + Unpack([]byte) (int, error)
28 + // Copy copies the Rdata.
29 + Copy(PrivateRdata) error
30 + // Len returns the length in octets of the Rdata.
31 + Len() int
32 +}
33 +
34 +// PrivateRR represents an RR that uses a PrivateRdata user-defined type.
35 +// It mocks normal RRs and implements dns.RR interface.
36 +type PrivateRR struct {
37 + Hdr RR_Header
38 + Data PrivateRdata
39 +}
40 +
41 +func mkPrivateRR(rrtype uint16) *PrivateRR {
42 + // Panics if RR is not an instance of PrivateRR.
43 + rrfunc, ok := typeToRR[rrtype]
44 + if !ok {
45 + panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
46 + }
47 +
48 + anyrr := rrfunc()
49 + switch rr := anyrr.(type) {
50 + case *PrivateRR:
51 + return rr
52 + }
53 + panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr))
54 +}
55 +
56 +func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
57 +func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
58 +
59 +// Private len and copy parts to satisfy RR interface.
60 +func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
61 +func (r *PrivateRR) copy() RR {
62 + // make new RR like this:
63 + rr := mkPrivateRR(r.Hdr.Rrtype)
64 + newh := r.Hdr.copyHeader()
65 + rr.Hdr = *newh
66 +
67 + err := r.Data.Copy(rr.Data)
68 + if err != nil {
69 + panic("dns: got value that could not be used to copy Private rdata")
70 + }
71 + return rr
72 +}
73 +
74 +// PrivateHandle registers a private resource record type. It requires
75 +// string and numeric representation of private RR type and generator function as argument.
76 +func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
77 + rtypestr = strings.ToUpper(rtypestr)
78 +
79 + typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
80 + TypeToString[rtype] = rtypestr
81 + StringToType[rtypestr] = rtype
82 +
83 + setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
84 + rr := mkPrivateRR(h.Rrtype)
85 + rr.Hdr = h
86 +
87 + var l lex
88 + text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
89 + FETCH:
90 + for {
91 + // TODO(miek): we could also be returning _QUOTE, this might or might not
92 + // be an issue (basically parsing TXT becomes hard)
93 + switch l = <-c; l.value {
94 + case _NEWLINE, _EOF:
95 + break FETCH
96 + case _STRING:
97 + text = append(text, l.token)
98 + }
99 + }
100 +
101 + err := rr.Data.Parse(text)
102 + if err != nil {
103 + return nil, &ParseError{f, err.Error(), l}, ""
104 + }
105 +
106 + return rr, nil, ""
107 + }
108 +
109 + typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
110 +}
111 +
112 +// PrivateHandleRemove removes defenitions required to support private RR type.
113 +func PrivateHandleRemove(rtype uint16) {
114 + rtypestr, ok := TypeToString[rtype]
115 + if ok {
116 + delete(typeToRR, rtype)
117 + delete(TypeToString, rtype)
118 + delete(typeToparserFunc, rtype)
119 + delete(StringToType, rtypestr)
120 + }
121 + return
122 +}
Godeps/_workspace/src/github.com/miekg/dns/privaterr_test.go new
+169
@@ -0,0 +1,169 @@
1 +package dns_test
2 +
3 +import (
4 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns"
5 + "strings"
6 + "testing"
7 +)
8 +
9 +const TypeISBN uint16 = 0x0F01
10 +
11 +// A crazy new RR type :)
12 +type ISBN struct {
13 + x string // rdata with 10 or 13 numbers, dashes or spaces allowed
14 +}
15 +
16 +func NewISBN() dns.PrivateRdata { return &ISBN{""} }
17 +
18 +func (rd *ISBN) Len() int { return len([]byte(rd.x)) }
19 +func (rd *ISBN) String() string { return rd.x }
20 +
21 +func (rd *ISBN) Parse(txt []string) error {
22 + rd.x = strings.TrimSpace(strings.Join(txt, " "))
23 + return nil
24 +}
25 +
26 +func (rd *ISBN) Pack(buf []byte) (int, error) {
27 + b := []byte(rd.x)
28 + n := copy(buf, b)
29 + if n != len(b) {
30 + return n, dns.ErrBuf
31 + }
32 + return n, nil
33 +}
34 +
35 +func (rd *ISBN) Unpack(buf []byte) (int, error) {
36 + rd.x = string(buf)
37 + return len(buf), nil
38 +}
39 +
40 +func (rd *ISBN) Copy(dest dns.PrivateRdata) error {
41 + isbn, ok := dest.(*ISBN)
42 + if !ok {
43 + return dns.ErrRdata
44 + }
45 + isbn.x = rd.x
46 + return nil
47 +}
48 +
49 +var testrecord = strings.Join([]string{"example.org.", "3600", "IN", "ISBN", "12-3 456789-0-123"}, "\t")
50 +
51 +func TestPrivateText(t *testing.T) {
52 + dns.PrivateHandle("ISBN", TypeISBN, NewISBN)
53 + defer dns.PrivateHandleRemove(TypeISBN)
54 +
55 + rr, err := dns.NewRR(testrecord)
56 + if err != nil {
57 + t.Fatal(err)
58 + }
59 + if rr.String() != testrecord {
60 + t.Errorf("record string representation did not match original %#v != %#v", rr.String(), testrecord)
61 + } else {
62 + t.Log(rr.String())
63 + }
64 +}
65 +
66 +func TestPrivateByteSlice(t *testing.T) {
67 + dns.PrivateHandle("ISBN", TypeISBN, NewISBN)
68 + defer dns.PrivateHandleRemove(TypeISBN)
69 +
70 + rr, err := dns.NewRR(testrecord)
71 + if err != nil {
72 + t.Fatal(err)
73 + }
74 +
75 + buf := make([]byte, 100)
76 + off, err := dns.PackRR(rr, buf, 0, nil, false)
77 + if err != nil {
78 + t.Errorf("got error packing ISBN: %s", err)
79 + }
80 +
81 + custrr := rr.(*dns.PrivateRR)
82 + if ln := custrr.Data.Len() + len(custrr.Header().Name) + 11; ln != off {
83 + t.Errorf("offset is not matching to length of Private RR: %d!=%d", off, ln)
84 + }
85 +
86 + rr1, off1, err := dns.UnpackRR(buf[:off], 0)
87 + if err != nil {
88 + t.Errorf("got error unpacking ISBN: %s", err)
89 + }
90 +
91 + if off1 != off {
92 + t.Errorf("Offset after unpacking differs: %d != %d", off1, off)
93 + }
94 +
95 + if rr1.String() != testrecord {
96 + t.Errorf("Record string representation did not match original %#v != %#v", rr1.String(), testrecord)
97 + } else {
98 + t.Log(rr1.String())
99 + }
100 +}
101 +
102 +const TypeVERSION uint16 = 0x0F02
103 +
104 +type VERSION struct {
105 + x string
106 +}
107 +
108 +func NewVersion() dns.PrivateRdata { return &VERSION{""} }
109 +
110 +func (rd *VERSION) String() string { return rd.x }
111 +func (rd *VERSION) Parse(txt []string) error {
112 + rd.x = strings.TrimSpace(strings.Join(txt, " "))
113 + return nil
114 +}
115 +
116 +func (rd *VERSION) Pack(buf []byte) (int, error) {
117 + b := []byte(rd.x)
118 + n := copy(buf, b)
119 + if n != len(b) {
120 + return n, dns.ErrBuf
121 + }
122 + return n, nil
123 +}
124 +
125 +func (rd *VERSION) Unpack(buf []byte) (int, error) {
126 + rd.x = string(buf)
127 + return len(buf), nil
128 +}
129 +
130 +func (rd *VERSION) Copy(dest dns.PrivateRdata) error {
131 + isbn, ok := dest.(*VERSION)
132 + if !ok {
133 + return dns.ErrRdata
134 + }
135 + isbn.x = rd.x
136 + return nil
137 +}
138 +
139 +func (rd *VERSION) Len() int {
140 + return len([]byte(rd.x))
141 +}
142 +
143 +var smallzone = `$ORIGIN example.org.
144 +@ SOA sns.dns.icann.org. noc.dns.icann.org. (
145 + 2014091518 7200 3600 1209600 3600
146 +)
147 + A 1.2.3.4
148 +ok ISBN 1231-92110-12
149 +go VERSION (
150 + 1.3.1 ; comment
151 +)
152 +www ISBN 1231-92110-16
153 +* CNAME @
154 +`
155 +
156 +func TestPrivateZoneParser(t *testing.T) {
157 + dns.PrivateHandle("ISBN", TypeISBN, NewISBN)
158 + dns.PrivateHandle("VERSION", TypeVERSION, NewVersion)
159 + defer dns.PrivateHandleRemove(TypeISBN)
160 + defer dns.PrivateHandleRemove(TypeVERSION)
161 +
162 + r := strings.NewReader(smallzone)
163 + for x := range dns.ParseZone(r, ".", "") {
164 + if err := x.Error; err != nil {
165 + t.Fatal(err)
166 + }
167 + t.Log(x.RR)
168 + }
169 +}
Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go new
+95
@@ -0,0 +1,95 @@
1 +package dns
2 +
3 +// These raw* functions do not use reflection, they directly set the values
4 +// in the buffer. There are faster than their reflection counterparts.
5 +
6 +// RawSetId sets the message id in buf.
7 +func rawSetId(msg []byte, i uint16) bool {
8 + if len(msg) < 2 {
9 + return false
10 + }
11 + msg[0], msg[1] = packUint16(i)
12 + return true
13 +}
14 +
15 +// rawSetQuestionLen sets the length of the question section.
16 +func rawSetQuestionLen(msg []byte, i uint16) bool {
17 + if len(msg) < 6 {
18 + return false
19 + }
20 + msg[4], msg[5] = packUint16(i)
21 + return true
22 +}
23 +
24 +// rawSetAnswerLen sets the lenght of the answer section.
25 +func rawSetAnswerLen(msg []byte, i uint16) bool {
26 + if len(msg) < 8 {
27 + return false
28 + }
29 + msg[6], msg[7] = packUint16(i)
30 + return true
31 +}
32 +
33 +// rawSetsNsLen sets the lenght of the authority section.
34 +func rawSetNsLen(msg []byte, i uint16) bool {
35 + if len(msg) < 10 {
36 + return false
37 + }
38 + msg[8], msg[9] = packUint16(i)
39 + return true
40 +}
41 +
42 +// rawSetExtraLen sets the lenght of the additional section.
43 +func rawSetExtraLen(msg []byte, i uint16) bool {
44 + if len(msg) < 12 {
45 + return false
46 + }
47 + msg[10], msg[11] = packUint16(i)
48 + return true
49 +}
50 +
51 +// rawSetRdlength sets the rdlength in the header of
52 +// the RR. The offset 'off' must be positioned at the
53 +// start of the header of the RR, 'end' must be the
54 +// end of the RR.
55 +func rawSetRdlength(msg []byte, off, end int) bool {
56 + l := len(msg)
57 +Loop:
58 + for {
59 + if off+1 > l {
60 + return false
61 + }
62 + c := int(msg[off])
63 + off++
64 + switch c & 0xC0 {
65 + case 0x00:
66 + if c == 0x00 {
67 + // End of the domainname
68 + break Loop
69 + }
70 + if off+c > l {
71 + return false
72 + }
73 + off += c
74 +
75 + case 0xC0:
76 + // pointer, next byte included, ends domainname
77 + off++
78 + break Loop
79 + }
80 + }
81 + // The domainname has been seen, we at the start of the fixed part in the header.
82 + // Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length.
83 + off += 2 + 2 + 4
84 + if off+2 > l {
85 + return false
86 + }
87 + //off+1 is the end of the header, 'end' is the end of the rr
88 + //so 'end' - 'off+2' is the length of the rdata
89 + rdatalen := end - (off + 2)
90 + if rdatalen > 0xFFFF {
91 + return false
92 + }
93 + msg[off], msg[off+1] = packUint16(uint16(rdatalen))
94 + return true
95 +}
Godeps/_workspace/src/github.com/miekg/dns/scanner.go new
+43
@@ -0,0 +1,43 @@
1 +package dns
2 +
3 +// Implement a simple scanner, return a byte stream from an io reader.
4 +
5 +import (
6 + "bufio"
7 + "io"
8 + "text/scanner"
9 +)
10 +
11 +type scan struct {
12 + src *bufio.Reader
13 + position scanner.Position
14 + eof bool // Have we just seen a eof
15 +}
16 +
17 +func scanInit(r io.Reader) *scan {
18 + s := new(scan)
19 + s.src = bufio.NewReader(r)
20 + s.position.Line = 1
21 + return s
22 +}
23 +
24 +// tokenText returns the next byte from the input
25 +func (s *scan) tokenText() (byte, error) {
26 + c, err := s.src.ReadByte()
27 + if err != nil {
28 + return c, err
29 + }
30 + // delay the newline handling until the next token is delivered,
31 + // fixes off-by-one errors when reporting a parse error.
32 + if s.eof == true {
33 + s.position.Line++
34 + s.position.Column = 0
35 + s.eof = false
36 + }
37 + if c == '\n' {
38 + s.eof = true
39 + return c, nil
40 + }
41 + s.position.Column++
42 + return c, nil
43 +}
Godeps/_workspace/src/github.com/miekg/dns/server.go new
+628
@@ -0,0 +1,628 @@
1 +// DNS server implementation.
2 +
3 +package dns
4 +
5 +import (
6 + "bytes"
7 + "io"
8 + "net"
9 + "sync"
10 + "time"
11 +)
12 +
13 +type Handler interface {
14 + ServeDNS(w ResponseWriter, r *Msg)
15 +}
16 +
17 +// A ResponseWriter interface is used by an DNS handler to
18 +// construct an DNS response.
19 +type ResponseWriter interface {
20 + // LocalAddr returns the net.Addr of the server
21 + LocalAddr() net.Addr
22 + // RemoteAddr returns the net.Addr of the client that sent the current request.
23 + RemoteAddr() net.Addr
24 + // WriteMsg writes a reply back to the client.
25 + WriteMsg(*Msg) error
26 + // Write writes a raw buffer back to the client.
27 + Write([]byte) (int, error)
28 + // Close closes the connection.
29 + Close() error
30 + // TsigStatus returns the status of the Tsig.
31 + TsigStatus() error
32 + // TsigTimersOnly sets the tsig timers only boolean.
33 + TsigTimersOnly(bool)
34 + // Hijack lets the caller take over the connection.
35 + // After a call to Hijack(), the DNS package will not do anything with the connection.
36 + Hijack()
37 +}
38 +
39 +type response struct {
40 + hijacked bool // connection has been hijacked by handler
41 + tsigStatus error
42 + tsigTimersOnly bool
43 + tsigRequestMAC string
44 + tsigSecret map[string]string // the tsig secrets
45 + udp *net.UDPConn // i/o connection if UDP was used
46 + tcp *net.TCPConn // i/o connection if TCP was used
47 + udpSession *sessionUDP // oob data to get egress interface right
48 + remoteAddr net.Addr // address of the client
49 +}
50 +
51 +// ServeMux is an DNS request multiplexer. It matches the
52 +// zone name of each incoming request against a list of
53 +// registered patterns add calls the handler for the pattern
54 +// that most closely matches the zone name. ServeMux is DNSSEC aware, meaning
55 +// that queries for the DS record are redirected to the parent zone (if that
56 +// is also registered), otherwise the child gets the query.
57 +// ServeMux is also safe for concurrent access from multiple goroutines.
58 +type ServeMux struct {
59 + z map[string]Handler
60 + m *sync.RWMutex
61 +}
62 +
63 +// NewServeMux allocates and returns a new ServeMux.
64 +func NewServeMux() *ServeMux { return &ServeMux{z: make(map[string]Handler), m: new(sync.RWMutex)} }
65 +
66 +// DefaultServeMux is the default ServeMux used by Serve.
67 +var DefaultServeMux = NewServeMux()
68 +
69 +// The HandlerFunc type is an adapter to allow the use of
70 +// ordinary functions as DNS handlers. If f is a function
71 +// with the appropriate signature, HandlerFunc(f) is a
72 +// Handler object that calls f.
73 +type HandlerFunc func(ResponseWriter, *Msg)
74 +
75 +// ServerDNS calls f(w, r)
76 +func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
77 + f(w, r)
78 +}
79 +
80 +// FailedHandler returns a HandlerFunc that returns SERVFAIL for every request it gets.
81 +func HandleFailed(w ResponseWriter, r *Msg) {
82 + m := new(Msg)
83 + m.SetRcode(r, RcodeServerFailure)
84 + // does not matter if this write fails
85 + w.WriteMsg(m)
86 +}
87 +
88 +func failedHandler() Handler { return HandlerFunc(HandleFailed) }
89 +
90 +// ListenAndServe Starts a server on addresss and network speficied. Invoke handler
91 +// for incoming queries.
92 +func ListenAndServe(addr string, network string, handler Handler) error {
93 + server := &Server{Addr: addr, Net: network, Handler: handler}
94 + return server.ListenAndServe()
95 +}
96 +
97 +// ActivateAndServe activates a server with a listener from systemd,
98 +// l and p should not both be non-nil.
99 +// If both l and p are not nil only p will be used.
100 +// Invoke handler for incoming queries.
101 +func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
102 + server := &Server{Listener: l, PacketConn: p, Handler: handler}
103 + return server.ActivateAndServe()
104 +}
105 +
106 +func (mux *ServeMux) match(q string, t uint16) Handler {
107 + mux.m.RLock()
108 + defer mux.m.RUnlock()
109 + var handler Handler
110 + b := make([]byte, len(q)) // worst case, one label of length q
111 + off := 0
112 + end := false
113 + for {
114 + l := len(q[off:])
115 + for i := 0; i < l; i++ {
116 + b[i] = q[off+i]
117 + if b[i] >= 'A' && b[i] <= 'Z' {
118 + b[i] |= ('a' - 'A')
119 + }
120 + }
121 + if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
122 + if t != TypeDS {
123 + return h
124 + } else {
125 + // Continue for DS to see if we have a parent too, if so delegeate to the parent
126 + handler = h
127 + }
128 + }
129 + off, end = NextLabel(q, off)
130 + if end {
131 + break
132 + }
133 + }
134 + // Wildcard match, if we have found nothing try the root zone as a last resort.
135 + if h, ok := mux.z["."]; ok {
136 + return h
137 + }
138 + return handler
139 +}
140 +
141 +// Handle adds a handler to the ServeMux for pattern.
142 +func (mux *ServeMux) Handle(pattern string, handler Handler) {
143 + if pattern == "" {
144 + panic("dns: invalid pattern " + pattern)
145 + }
146 + mux.m.Lock()
147 + mux.z[Fqdn(pattern)] = handler
148 + mux.m.Unlock()
149 +}
150 +
151 +// Handle adds a handler to the ServeMux for pattern.
152 +func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
153 + mux.Handle(pattern, HandlerFunc(handler))
154 +}
155 +
156 +// HandleRemove deregistrars the handler specific for pattern from the ServeMux.
157 +func (mux *ServeMux) HandleRemove(pattern string) {
158 + if pattern == "" {
159 + panic("dns: invalid pattern " + pattern)
160 + }
161 + // don't need a mutex here, because deleting is OK, even if the
162 + // entry is note there.
163 + delete(mux.z, Fqdn(pattern))
164 +}
165 +
166 +// ServeDNS dispatches the request to the handler whose
167 +// pattern most closely matches the request message. If DefaultServeMux
168 +// is used the correct thing for DS queries is done: a possible parent
169 +// is sought.
170 +// If no handler is found a standard SERVFAIL message is returned
171 +// If the request message does not have exactly one question in the
172 +// question section a SERVFAIL is returned, unlesss Unsafe is true.
173 +func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
174 + var h Handler
175 + if len(request.Question) < 1 { // allow more than one question
176 + h = failedHandler()
177 + } else {
178 + if h = mux.match(request.Question[0].Name, request.Question[0].Qtype); h == nil {
179 + h = failedHandler()
180 + }
181 + }
182 + h.ServeDNS(w, request)
183 +}
184 +
185 +// Handle registers the handler with the given pattern
186 +// in the DefaultServeMux. The documentation for
187 +// ServeMux explains how patterns are matched.
188 +func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
189 +
190 +// HandleRemove deregisters the handle with the given pattern
191 +// in the DefaultServeMux.
192 +func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
193 +
194 +// HandleFunc registers the handler function with the given pattern
195 +// in the DefaultServeMux.
196 +func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
197 + DefaultServeMux.HandleFunc(pattern, handler)
198 +}
199 +
200 +// A Server defines parameters for running an DNS server.
201 +type Server struct {
202 + // Address to listen on, ":dns" if empty.
203 + Addr string
204 + // if "tcp" it will invoke a TCP listener, otherwise an UDP one.
205 + Net string
206 + // TCP Listener to use, this is to aid in systemd's socket activation.
207 + Listener net.Listener
208 + // UDP "Listener" to use, this is to aid in systemd's socket activation.
209 + PacketConn net.PacketConn
210 + // Handler to invoke, dns.DefaultServeMux if nil.
211 + Handler Handler
212 + // Default buffer size to use to read incoming UDP messages. If not set
213 + // it defaults to MinMsgSize (512 B).
214 + UDPSize int
215 + // The net.Conn.SetReadTimeout value for new connections, defaults to 2 * time.Second.
216 + ReadTimeout time.Duration
217 + // The net.Conn.SetWriteTimeout value for new connections, defaults to 2 * time.Second.
218 + WriteTimeout time.Duration
219 + // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
220 + IdleTimeout func() time.Duration
221 + // Secret(s) for Tsig map[<zonename>]<base64 secret>.
222 + TsigSecret map[string]string
223 + // Unsafe instructs the server to disregard any sanity checks and directly hand the message to
224 + // the handler. It will specfically not check if the query has the QR bit not set.
225 + Unsafe bool
226 + // If NotifyStartedFunc is set is is called, once the server has started listening.
227 + NotifyStartedFunc func()
228 +
229 + // For graceful shutdown.
230 + stopUDP chan bool
231 + stopTCP chan bool
232 + wgUDP sync.WaitGroup
233 + wgTCP sync.WaitGroup
234 +
235 + // make start/shutdown not racy
236 + lock sync.Mutex
237 + started bool
238 +}
239 +
240 +// ListenAndServe starts a nameserver on the configured address in *Server.
241 +func (srv *Server) ListenAndServe() error {
242 + srv.lock.Lock()
243 + if srv.started {
244 + srv.lock.Unlock()
245 + return &Error{err: "server already started"}
246 + }
247 + srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
248 + srv.started = true
249 + srv.lock.Unlock()
250 + addr := srv.Addr
251 + if addr == "" {
252 + addr = ":domain"
253 + }
254 + if srv.UDPSize == 0 {
255 + srv.UDPSize = MinMsgSize
256 + }
257 + switch srv.Net {
258 + case "tcp", "tcp4", "tcp6":
259 + a, e := net.ResolveTCPAddr(srv.Net, addr)
260 + if e != nil {
261 + return e
262 + }
263 + l, e := net.ListenTCP(srv.Net, a)
264 + if e != nil {
265 + return e
266 + }
267 + return srv.serveTCP(l)
268 + case "udp", "udp4", "udp6":
269 + a, e := net.ResolveUDPAddr(srv.Net, addr)
270 + if e != nil {
271 + return e
272 + }
273 + l, e := net.ListenUDP(srv.Net, a)
274 + if e != nil {
275 + return e
276 + }
277 + if e := setUDPSocketOptions(l); e != nil {
278 + return e
279 + }
280 + return srv.serveUDP(l)
281 + }
282 + return &Error{err: "bad network"}
283 +}
284 +
285 +// ActivateAndServe starts a nameserver with the PacketConn or Listener
286 +// configured in *Server. Its main use is to start a server from systemd.
287 +func (srv *Server) ActivateAndServe() error {
288 + srv.lock.Lock()
289 + if srv.started {
290 + srv.lock.Unlock()
291 + return &Error{err: "server already started"}
292 + }
293 + srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
294 + srv.started = true
295 + srv.lock.Unlock()
296 + if srv.PacketConn != nil {
297 + if srv.UDPSize == 0 {
298 + srv.UDPSize = MinMsgSize
299 + }
300 + if t, ok := srv.PacketConn.(*net.UDPConn); ok {
301 + if e := setUDPSocketOptions(t); e != nil {
302 + return e
303 + }
304 + return srv.serveUDP(t)
305 + }
306 + }
307 + if srv.Listener != nil {
308 + if t, ok := srv.Listener.(*net.TCPListener); ok {
309 + return srv.serveTCP(t)
310 + }
311 + }
312 + return &Error{err: "bad listeners"}
313 +}
314 +
315 +// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
316 +// ActivateAndServe will return. All in progress queries are completed before the server
317 +// is taken down. If the Shutdown is taking longer than the reading timeout and error
318 +// is returned.
319 +func (srv *Server) Shutdown() error {
320 + srv.lock.Lock()
321 + if !srv.started {
322 + srv.lock.Unlock()
323 + return &Error{err: "server not started"}
324 + }
325 + srv.started = false
326 + srv.lock.Unlock()
327 + net, addr := srv.Net, srv.Addr
328 + switch {
329 + case srv.Listener != nil:
330 + a := srv.Listener.Addr()
331 + net, addr = a.Network(), a.String()
332 + case srv.PacketConn != nil:
333 + a := srv.PacketConn.LocalAddr()
334 + net, addr = a.Network(), a.String()
335 + }
336 +
337 + fin := make(chan bool)
338 + switch net {
339 + case "tcp", "tcp4", "tcp6":
340 + go func() {
341 + srv.stopTCP <- true
342 + srv.wgTCP.Wait()
343 + fin <- true
344 + }()
345 +
346 + case "udp", "udp4", "udp6":
347 + go func() {
348 + srv.stopUDP <- true
349 + srv.wgUDP.Wait()
350 + fin <- true
351 + }()
352 + }
353 +
354 + c := &Client{Net: net}
355 + go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
356 +
357 + select {
358 + case <-time.After(srv.getReadTimeout()):
359 + return &Error{err: "server shutdown is pending"}
360 + case <-fin:
361 + return nil
362 + }
363 +}
364 +
365 +// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
366 +func (srv *Server) getReadTimeout() time.Duration {
367 + rtimeout := dnsTimeout
368 + if srv.ReadTimeout != 0 {
369 + rtimeout = srv.ReadTimeout
370 + }
371 + return rtimeout
372 +}
373 +
374 +// serveTCP starts a TCP listener for the server.
375 +// Each request is handled in a seperate goroutine.
376 +func (srv *Server) serveTCP(l *net.TCPListener) error {
377 + defer l.Close()
378 +
379 + if srv.NotifyStartedFunc != nil {
380 + srv.NotifyStartedFunc()
381 + }
382 +
383 + handler := srv.Handler
384 + if handler == nil {
385 + handler = DefaultServeMux
386 + }
387 + rtimeout := srv.getReadTimeout()
388 + // deadline is not used here
389 + for {
390 + rw, e := l.AcceptTCP()
391 + if e != nil {
392 + continue
393 + }
394 + m, e := srv.readTCP(rw, rtimeout)
395 + select {
396 + case <-srv.stopTCP:
397 + return nil
398 + default:
399 + }
400 + if e != nil {
401 + continue
402 + }
403 + srv.wgTCP.Add(1)
404 + go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
405 + }
406 + panic("dns: not reached")
407 +}
408 +
409 +// serveUDP starts a UDP listener for the server.
410 +// Each request is handled in a seperate goroutine.
411 +func (srv *Server) serveUDP(l *net.UDPConn) error {
412 + defer l.Close()
413 +
414 + if srv.NotifyStartedFunc != nil {
415 + srv.NotifyStartedFunc()
416 + }
417 +
418 + handler := srv.Handler
419 + if handler == nil {
420 + handler = DefaultServeMux
421 + }
422 + rtimeout := srv.getReadTimeout()
423 + // deadline is not used here
424 + for {
425 + m, s, e := srv.readUDP(l, rtimeout)
426 + select {
427 + case <-srv.stopUDP:
428 + return nil
429 + default:
430 + }
431 + if e != nil {
432 + continue
433 + }
434 + srv.wgUDP.Add(1)
435 + go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
436 + }
437 + panic("dns: not reached")
438 +}
439 +
440 +// Serve a new connection.
441 +func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *sessionUDP, t *net.TCPConn) {
442 + w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
443 + q := 0
444 + defer func() {
445 + if u != nil {
446 + srv.wgUDP.Done()
447 + }
448 + if t != nil {
449 + srv.wgTCP.Done()
450 + }
451 + }()
452 +Redo:
453 + req := new(Msg)
454 + err := req.Unpack(m)
455 + if err != nil { // Send a FormatError back
456 + x := new(Msg)
457 + x.SetRcodeFormatError(req)
458 + w.WriteMsg(x)
459 + goto Exit
460 + }
461 + if !srv.Unsafe && req.Response {
462 + goto Exit
463 + }
464 +
465 + w.tsigStatus = nil
466 + if w.tsigSecret != nil {
467 + if t := req.IsTsig(); t != nil {
468 + secret := t.Hdr.Name
469 + if _, ok := w.tsigSecret[secret]; !ok {
470 + w.tsigStatus = ErrKeyAlg
471 + }
472 + w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false)
473 + w.tsigTimersOnly = false
474 + w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
475 + }
476 + }
477 + h.ServeDNS(w, req) // Writes back to the client
478 +
479 +Exit:
480 + if w.hijacked {
481 + return // client calls Close()
482 + }
483 + if u != nil { // UDP, "close" and return
484 + w.Close()
485 + return
486 + }
487 + idleTimeout := tcpIdleTimeout
488 + if srv.IdleTimeout != nil {
489 + idleTimeout = srv.IdleTimeout()
490 + }
491 + m, e := srv.readTCP(w.tcp, idleTimeout)
492 + if e == nil {
493 + q++
494 + // TODO(miek): make this number configurable?
495 + if q > 128 { // close socket after this many queries
496 + w.Close()
497 + return
498 + }
499 + goto Redo
500 + }
501 + w.Close()
502 + return
503 +}
504 +
505 +func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
506 + conn.SetReadDeadline(time.Now().Add(timeout))
507 + l := make([]byte, 2)
508 + n, err := conn.Read(l)
509 + if err != nil || n != 2 {
510 + if err != nil {
511 + return nil, err
512 + }
513 + return nil, ErrShortRead
514 + }
515 + length, _ := unpackUint16(l, 0)
516 + if length == 0 {
517 + return nil, ErrShortRead
518 + }
519 + m := make([]byte, int(length))
520 + n, err = conn.Read(m[:int(length)])
521 + if err != nil || n == 0 {
522 + if err != nil {
523 + return nil, err
524 + }
525 + return nil, ErrShortRead
526 + }
527 + i := n
528 + for i < int(length) {
529 + j, err := conn.Read(m[i:int(length)])
530 + if err != nil {
531 + return nil, err
532 + }
533 + i += j
534 + }
535 + n = i
536 + m = m[:n]
537 + return m, nil
538 +}
539 +
540 +func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) {
541 + conn.SetReadDeadline(time.Now().Add(timeout))
542 + m := make([]byte, srv.UDPSize)
543 + n, s, e := readFromSessionUDP(conn, m)
544 + if e != nil || n == 0 {
545 + if e != nil {
546 + return nil, nil, e
547 + }
548 + return nil, nil, ErrShortRead
549 + }
550 + m = m[:n]
551 + return m, s, nil
552 +}
553 +
554 +// WriteMsg implements the ResponseWriter.WriteMsg method.
555 +func (w *response) WriteMsg(m *Msg) (err error) {
556 + var data []byte
557 + if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
558 + if t := m.IsTsig(); t != nil {
559 + data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
560 + if err != nil {
561 + return err
562 + }
563 + _, err = w.Write(data)
564 + return err
565 + }
566 + }
567 + data, err = m.Pack()
568 + if err != nil {
569 + return err
570 + }
571 + _, err = w.Write(data)
572 + return err
573 +}
574 +
575 +// Write implements the ResponseWriter.Write method.
576 +func (w *response) Write(m []byte) (int, error) {
577 + switch {
578 + case w.udp != nil:
579 + n, err := writeToSessionUDP(w.udp, m, w.udpSession)
580 + return n, err
581 + case w.tcp != nil:
582 + lm := len(m)
583 + if lm < 2 {
584 + return 0, io.ErrShortBuffer
585 + }
586 + if lm > MaxMsgSize {
587 + return 0, &Error{err: "message too large"}
588 + }
589 + l := make([]byte, 2, 2+lm)
590 + l[0], l[1] = packUint16(uint16(lm))
591 + m = append(l, m...)
592 +
593 + n, err := io.Copy(w.tcp, bytes.NewReader(m))
594 + return int(n), err
595 + }
596 + panic("not reached")
597 +}
598 +
599 +// LocalAddr implements the ResponseWriter.LocalAddr method.
600 +func (w *response) LocalAddr() net.Addr {
601 + if w.tcp != nil {
602 + return w.tcp.LocalAddr()
603 + }
604 + return w.udp.LocalAddr()
605 +}
606 +
607 +// RemoteAddr implements the ResponseWriter.RemoteAddr method.
608 +func (w *response) RemoteAddr() net.Addr { return w.remoteAddr }
609 +
610 +// TsigStatus implements the ResponseWriter.TsigStatus method.
611 +func (w *response) TsigStatus() error { return w.tsigStatus }
612 +
613 +// TsigTimersOnly implements the ResponseWriter.TsigTimersOnly method.
614 +func (w *response) TsigTimersOnly(b bool) { w.tsigTimersOnly = b }
615 +
616 +// Hijack implements the ResponseWriter.Hijack method.
617 +func (w *response) Hijack() { w.hijacked = true }
618 +
619 +// Close implements the ResponseWriter.Close method
620 +func (w *response) Close() error {
621 + // Can't close the udp conn, as that is actually the listener.
622 + if w.tcp != nil {
623 + e := w.tcp.Close()
624 + w.tcp = nil
625 + return e
626 + }
627 + return nil
628 +}
Godeps/_workspace/src/github.com/miekg/dns/server_test.go new
+401
@@ -0,0 +1,401 @@
1 +package dns
2 +
3 +import (
4 + "fmt"
5 + "net"
6 + "runtime"
7 + "sync"
8 + "testing"
9 +)
10 +
11 +func HelloServer(w ResponseWriter, req *Msg) {
12 + m := new(Msg)
13 + m.SetReply(req)
14 +
15 + m.Extra = make([]RR, 1)
16 + m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
17 + w.WriteMsg(m)
18 +}
19 +
20 +func AnotherHelloServer(w ResponseWriter, req *Msg) {
21 + m := new(Msg)
22 + m.SetReply(req)
23 +
24 + m.Extra = make([]RR, 1)
25 + m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
26 + w.WriteMsg(m)
27 +}
28 +
29 +func RunLocalUDPServer(laddr string) (*Server, string, error) {
30 + pc, err := net.ListenPacket("udp", laddr)
31 + if err != nil {
32 + return nil, "", err
33 + }
34 + server := &Server{PacketConn: pc}
35 +
36 + waitLock := sync.Mutex{}
37 + waitLock.Lock()
38 + server.NotifyStartedFunc = waitLock.Unlock
39 +
40 + go func() {
41 + server.ActivateAndServe()
42 + pc.Close()
43 + }()
44 +
45 + waitLock.Lock()
46 + return server, pc.LocalAddr().String(), nil
47 +}
48 +
49 +func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
50 + pc, err := net.ListenPacket("udp", laddr)
51 + if err != nil {
52 + return nil, "", err
53 + }
54 + server := &Server{PacketConn: pc, Unsafe: true}
55 +
56 + waitLock := sync.Mutex{}
57 + waitLock.Lock()
58 + server.NotifyStartedFunc = waitLock.Unlock
59 +
60 + go func() {
61 + server.ActivateAndServe()
62 + pc.Close()
63 + }()
64 +
65 + waitLock.Lock()
66 + return server, pc.LocalAddr().String(), nil
67 +}
68 +
69 +func RunLocalTCPServer(laddr string) (*Server, string, error) {
70 + l, err := net.Listen("tcp", laddr)
71 + if err != nil {
72 + return nil, "", err
73 + }
74 +
75 + server := &Server{Listener: l}
76 +
77 + waitLock := sync.Mutex{}
78 + waitLock.Lock()
79 + server.NotifyStartedFunc = waitLock.Unlock
80 +
81 + go func() {
82 + server.ActivateAndServe()
83 + l.Close()
84 + }()
85 +
86 + waitLock.Lock()
87 + return server, l.Addr().String(), nil
88 +}
89 +
90 +func TestServing(t *testing.T) {
91 + HandleFunc("miek.nl.", HelloServer)
92 + HandleFunc("example.com.", AnotherHelloServer)
93 + defer HandleRemove("miek.nl.")
94 + defer HandleRemove("example.com.")
95 +
96 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
97 + if err != nil {
98 + t.Fatalf("Unable to run test server: %s", err)
99 + }
100 + defer s.Shutdown()
101 +
102 + c := new(Client)
103 + m := new(Msg)
104 + m.SetQuestion("miek.nl.", TypeTXT)
105 + r, _, err := c.Exchange(m, addrstr)
106 + if err != nil || len(r.Extra) == 0 {
107 + t.Log("failed to exchange miek.nl", err)
108 + t.Fatal()
109 + }
110 + txt := r.Extra[0].(*TXT).Txt[0]
111 + if txt != "Hello world" {
112 + t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
113 + t.Fail()
114 + }
115 +
116 + m.SetQuestion("example.com.", TypeTXT)
117 + r, _, err = c.Exchange(m, addrstr)
118 + if err != nil {
119 + t.Log("failed to exchange example.com", err)
120 + t.Fatal()
121 + }
122 + txt = r.Extra[0].(*TXT).Txt[0]
123 + if txt != "Hello example" {
124 + t.Log("Unexpected result for example.com", txt, "!= Hello example")
125 + t.Fail()
126 + }
127 +
128 + // Test Mixes cased as noticed by Ask.
129 + m.SetQuestion("eXaMplE.cOm.", TypeTXT)
130 + r, _, err = c.Exchange(m, addrstr)
131 + if err != nil {
132 + t.Log("failed to exchange eXaMplE.cOm", err)
133 + t.Fail()
134 + }
135 + txt = r.Extra[0].(*TXT).Txt[0]
136 + if txt != "Hello example" {
137 + t.Log("Unexpected result for example.com", txt, "!= Hello example")
138 + t.Fail()
139 + }
140 +}
141 +
142 +func BenchmarkServe(b *testing.B) {
143 + b.StopTimer()
144 + HandleFunc("miek.nl.", HelloServer)
145 + defer HandleRemove("miek.nl.")
146 + a := runtime.GOMAXPROCS(4)
147 +
148 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
149 + if err != nil {
150 + b.Fatalf("Unable to run test server: %s", err)
151 + }
152 + defer s.Shutdown()
153 +
154 + c := new(Client)
155 + m := new(Msg)
156 + m.SetQuestion("miek.nl", TypeSOA)
157 +
158 + b.StartTimer()
159 + for i := 0; i < b.N; i++ {
160 + c.Exchange(m, addrstr)
161 + }
162 + runtime.GOMAXPROCS(a)
163 +}
164 +
165 +func benchmarkServe6(b *testing.B) {
166 + b.StopTimer()
167 + HandleFunc("miek.nl.", HelloServer)
168 + defer HandleRemove("miek.nl.")
169 + a := runtime.GOMAXPROCS(4)
170 + s, addrstr, err := RunLocalUDPServer("[::1]:0")
171 + if err != nil {
172 + b.Fatalf("Unable to run test server: %s", err)
173 + }
174 + defer s.Shutdown()
175 +
176 + c := new(Client)
177 + m := new(Msg)
178 + m.SetQuestion("miek.nl", TypeSOA)
179 +
180 + b.StartTimer()
181 + for i := 0; i < b.N; i++ {
182 + c.Exchange(m, addrstr)
183 + }
184 + runtime.GOMAXPROCS(a)
185 +}
186 +
187 +func HelloServerCompress(w ResponseWriter, req *Msg) {
188 + m := new(Msg)
189 + m.SetReply(req)
190 + m.Extra = make([]RR, 1)
191 + m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
192 + m.Compress = true
193 + w.WriteMsg(m)
194 +}
195 +
196 +func BenchmarkServeCompress(b *testing.B) {
197 + b.StopTimer()
198 + HandleFunc("miek.nl.", HelloServerCompress)
199 + defer HandleRemove("miek.nl.")
200 + a := runtime.GOMAXPROCS(4)
201 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
202 + if err != nil {
203 + b.Fatalf("Unable to run test server: %s", err)
204 + }
205 + defer s.Shutdown()
206 +
207 + c := new(Client)
208 + m := new(Msg)
209 + m.SetQuestion("miek.nl", TypeSOA)
210 + b.StartTimer()
211 + for i := 0; i < b.N; i++ {
212 + c.Exchange(m, addrstr)
213 + }
214 + runtime.GOMAXPROCS(a)
215 +}
216 +
217 +func TestDotAsCatchAllWildcard(t *testing.T) {
218 + mux := NewServeMux()
219 + mux.Handle(".", HandlerFunc(HelloServer))
220 + mux.Handle("example.com.", HandlerFunc(AnotherHelloServer))
221 +
222 + handler := mux.match("www.miek.nl.", TypeTXT)
223 + if handler == nil {
224 + t.Error("wildcard match failed")
225 + }
226 +
227 + handler = mux.match("www.example.com.", TypeTXT)
228 + if handler == nil {
229 + t.Error("example.com match failed")
230 + }
231 +
232 + handler = mux.match("a.www.example.com.", TypeTXT)
233 + if handler == nil {
234 + t.Error("a.www.example.com match failed")
235 + }
236 +
237 + handler = mux.match("boe.", TypeTXT)
238 + if handler == nil {
239 + t.Error("boe. match failed")
240 + }
241 +}
242 +
243 +func TestCaseFolding(t *testing.T) {
244 + mux := NewServeMux()
245 + mux.Handle("_udp.example.com.", HandlerFunc(HelloServer))
246 +
247 + handler := mux.match("_dns._udp.example.com.", TypeSRV)
248 + if handler == nil {
249 + t.Error("case sensitive characters folded")
250 + }
251 +
252 + handler = mux.match("_DNS._UDP.EXAMPLE.COM.", TypeSRV)
253 + if handler == nil {
254 + t.Error("case insensitive characters not folded")
255 + }
256 +}
257 +
258 +func TestRootServer(t *testing.T) {
259 + mux := NewServeMux()
260 + mux.Handle(".", HandlerFunc(HelloServer))
261 +
262 + handler := mux.match(".", TypeNS)
263 + if handler == nil {
264 + t.Error("root match failed")
265 + }
266 +}
267 +
268 +type maxRec struct {
269 + max int
270 + sync.RWMutex
271 +}
272 +
273 +var M = new(maxRec)
274 +
275 +func HelloServerLargeResponse(resp ResponseWriter, req *Msg) {
276 + m := new(Msg)
277 + m.SetReply(req)
278 + m.Authoritative = true
279 + m1 := 0
280 + M.RLock()
281 + m1 = M.max
282 + M.RUnlock()
283 + for i := 0; i < m1; i++ {
284 + aRec := &A{
285 + Hdr: RR_Header{
286 + Name: req.Question[0].Name,
287 + Rrtype: TypeA,
288 + Class: ClassINET,
289 + Ttl: 0,
290 + },
291 + A: net.ParseIP(fmt.Sprintf("127.0.0.%d", i+1)).To4(),
292 + }
293 + m.Answer = append(m.Answer, aRec)
294 + }
295 + resp.WriteMsg(m)
296 +}
297 +
298 +func TestServingLargeResponses(t *testing.T) {
299 + HandleFunc("example.", HelloServerLargeResponse)
300 + defer HandleRemove("example.")
301 +
302 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
303 + if err != nil {
304 + t.Fatalf("Unable to run test server: %s", err)
305 + }
306 + defer s.Shutdown()
307 +
308 + // Create request
309 + m := new(Msg)
310 + m.SetQuestion("web.service.example.", TypeANY)
311 +
312 + c := new(Client)
313 + c.Net = "udp"
314 + M.Lock()
315 + M.max = 2
316 + M.Unlock()
317 + _, _, err = c.Exchange(m, addrstr)
318 + if err != nil {
319 + t.Logf("failed to exchange: %s", err.Error())
320 + t.Fail()
321 + }
322 + // This must fail
323 + M.Lock()
324 + M.max = 20
325 + M.Unlock()
326 + _, _, err = c.Exchange(m, addrstr)
327 + if err == nil {
328 + t.Logf("failed to fail exchange, this should generate packet error")
329 + t.Fail()
330 + }
331 + // But this must work again
332 + c.UDPSize = 7000
333 + _, _, err = c.Exchange(m, addrstr)
334 + if err != nil {
335 + t.Logf("failed to exchange: %s", err.Error())
336 + t.Fail()
337 + }
338 +}
339 +
340 +func TestServingResponse(t *testing.T) {
341 + if testing.Short() {
342 + t.Skip("skipping test in short mode.")
343 + }
344 + HandleFunc("miek.nl.", HelloServer)
345 + s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
346 + if err != nil {
347 + t.Fatalf("Unable to run test server: %s", err)
348 + }
349 +
350 + c := new(Client)
351 + m := new(Msg)
352 + m.SetQuestion("miek.nl.", TypeTXT)
353 + m.Response = false
354 + _, _, err = c.Exchange(m, addrstr)
355 + if err != nil {
356 + t.Log("failed to exchange", err)
357 + t.Fatal()
358 + }
359 + m.Response = true
360 + _, _, err = c.Exchange(m, addrstr)
361 + if err == nil {
362 + t.Log("exchanged response message")
363 + t.Fatal()
364 + }
365 +
366 + s.Shutdown()
367 + s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
368 + if err != nil {
369 + t.Fatalf("Unable to run test server: %s", err)
370 + }
371 + defer s.Shutdown()
372 +
373 + m.Response = true
374 + _, _, err = c.Exchange(m, addrstr)
375 + if err != nil {
376 + t.Log("could exchanged response message in Unsafe mode")
377 + t.Fatal()
378 + }
379 +}
380 +
381 +func TestShutdownTCP(t *testing.T) {
382 + s, _, err := RunLocalTCPServer("127.0.0.1:0")
383 + if err != nil {
384 + t.Fatalf("Unable to run test server: %s", err)
385 + }
386 + err = s.Shutdown()
387 + if err != nil {
388 + t.Errorf("Could not shutdown test TCP server, %s", err)
389 + }
390 +}
391 +
392 +func TestShutdownUDP(t *testing.T) {
393 + s, _, err := RunLocalUDPServer("127.0.0.1:0")
394 + if err != nil {
395 + t.Fatalf("Unable to run test server: %s", err)
396 + }
397 + err = s.Shutdown()
398 + if err != nil {
399 + t.Errorf("Could not shutdown test UDP server, %s", err)
400 + }
401 +}
Godeps/_workspace/src/github.com/miekg/dns/sig0.go new
+236
@@ -0,0 +1,236 @@
1 +// SIG(0)
2 +//
3 +// From RFC 2931:
4 +//
5 +// SIG(0) provides protection for DNS transactions and requests ....
6 +// ... protection for glue records, DNS requests, protection for message headers
7 +// on requests and responses, and protection of the overall integrity of a response.
8 +//
9 +// It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
10 +// secret approach in TSIG.
11 +// Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
12 +// RSASHA512.
13 +//
14 +// Signing subsequent messages in multi-message sessions is not implemented.
15 +//
16 +package dns
17 +
18 +import (
19 + "crypto"
20 + "crypto/dsa"
21 + "crypto/ecdsa"
22 + "crypto/rsa"
23 + "math/big"
24 + "strings"
25 + "time"
26 +)
27 +
28 +// Sign signs a dns.Msg. It fills the signature with the appropriate data.
29 +// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
30 +// and Expiration set.
31 +func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
32 + if k == nil {
33 + return nil, ErrPrivKey
34 + }
35 + if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
36 + return nil, ErrKey
37 + }
38 + rr.Header().Rrtype = TypeSIG
39 + rr.Header().Class = ClassANY
40 + rr.Header().Ttl = 0
41 + rr.Header().Name = "."
42 + rr.OrigTtl = 0
43 + rr.TypeCovered = 0
44 + rr.Labels = 0
45 +
46 + buf := make([]byte, m.Len()+rr.len())
47 + mbuf, err := m.PackBuffer(buf)
48 + if err != nil {
49 + return nil, err
50 + }
51 + if &buf[0] != &mbuf[0] {
52 + return nil, ErrBuf
53 + }
54 + off, err := PackRR(rr, buf, len(mbuf), nil, false)
55 + if err != nil {
56 + return nil, err
57 + }
58 + buf = buf[:off:cap(buf)]
59 + var hash crypto.Hash
60 + switch rr.Algorithm {
61 + case DSA, RSASHA1:
62 + hash = crypto.SHA1
63 + case RSASHA256, ECDSAP256SHA256:
64 + hash = crypto.SHA256
65 + case ECDSAP384SHA384:
66 + hash = crypto.SHA384
67 + case RSASHA512:
68 + hash = crypto.SHA512
69 + default:
70 + return nil, ErrAlg
71 + }
72 + hasher := hash.New()
73 + // Write SIG rdata
74 + hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
75 + // Write message
76 + hasher.Write(buf[:len(mbuf)])
77 + hashed := hasher.Sum(nil)
78 +
79 + sig, err := k.Sign(hashed, rr.Algorithm)
80 + if err != nil {
81 + return nil, err
82 + }
83 + rr.Signature = toBase64(sig)
84 + buf = append(buf, sig...)
85 + if len(buf) > int(^uint16(0)) {
86 + return nil, ErrBuf
87 + }
88 + // Adjust sig data length
89 + rdoff := len(mbuf) + 1 + 2 + 2 + 4
90 + rdlen, _ := unpackUint16(buf, rdoff)
91 + rdlen += uint16(len(sig))
92 + buf[rdoff], buf[rdoff+1] = packUint16(rdlen)
93 + // Adjust additional count
94 + adc, _ := unpackUint16(buf, 10)
95 + adc += 1
96 + buf[10], buf[11] = packUint16(adc)
97 + return buf, nil
98 +}
99 +
100 +// Verify validates the message buf using the key k.
101 +// It's assumed that buf is a valid message from which rr was unpacked.
102 +func (rr *SIG) Verify(k *KEY, buf []byte) error {
103 + if k == nil {
104 + return ErrKey
105 + }
106 + if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
107 + return ErrKey
108 + }
109 +
110 + var hash crypto.Hash
111 + switch rr.Algorithm {
112 + case DSA, RSASHA1:
113 + hash = crypto.SHA1
114 + case RSASHA256, ECDSAP256SHA256:
115 + hash = crypto.SHA256
116 + case ECDSAP384SHA384:
117 + hash = crypto.SHA384
118 + case RSASHA512:
119 + hash = crypto.SHA512
120 + default:
121 + return ErrAlg
122 + }
123 + hasher := hash.New()
124 +
125 + buflen := len(buf)
126 + qdc, _ := unpackUint16(buf, 4)
127 + anc, _ := unpackUint16(buf, 6)
128 + auc, _ := unpackUint16(buf, 8)
129 + adc, offset := unpackUint16(buf, 10)
130 + var err error
131 + for i := uint16(0); i < qdc && offset < buflen; i++ {
132 + _, offset, err = UnpackDomainName(buf, offset)
133 + if err != nil {
134 + return err
135 + }
136 + // Skip past Type and Class
137 + offset += 2 + 2
138 + }
139 + for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ {
140 + _, offset, err = UnpackDomainName(buf, offset)
141 + if err != nil {
142 + return err
143 + }
144 + // Skip past Type, Class and TTL
145 + offset += 2 + 2 + 4
146 + if offset+1 >= buflen {
147 + continue
148 + }
149 + var rdlen uint16
150 + rdlen, offset = unpackUint16(buf, offset)
151 + offset += int(rdlen)
152 + }
153 + if offset >= buflen {
154 + return &Error{err: "overflowing unpacking signed message"}
155 + }
156 +
157 + // offset should be just prior to SIG
158 + bodyend := offset
159 + // owner name SHOULD be root
160 + _, offset, err = UnpackDomainName(buf, offset)
161 + if err != nil {
162 + return err
163 + }
164 + // Skip Type, Class, TTL, RDLen
165 + offset += 2 + 2 + 4 + 2
166 + sigstart := offset
167 + // Skip Type Covered, Algorithm, Labels, Original TTL
168 + offset += 2 + 1 + 1 + 4
169 + if offset+4+4 >= buflen {
170 + return &Error{err: "overflow unpacking signed message"}
171 + }
172 + expire := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3])
173 + offset += 4
174 + incept := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3])
175 + offset += 4
176 + now := uint32(time.Now().Unix())
177 + if now < incept || now > expire {
178 + return ErrTime
179 + }
180 + // Skip key tag
181 + offset += 2
182 + var signername string
183 + signername, offset, err = UnpackDomainName(buf, offset)
184 + if err != nil {
185 + return err
186 + }
187 + // If key has come from the DNS name compression might
188 + // have mangled the case of the name
189 + if strings.ToLower(signername) != strings.ToLower(k.Header().Name) {
190 + return &Error{err: "signer name doesn't match key name"}
191 + }
192 + sigend := offset
193 + hasher.Write(buf[sigstart:sigend])
194 + hasher.Write(buf[:10])
195 + hasher.Write([]byte{
196 + byte((adc - 1) << 8),
197 + byte(adc - 1),
198 + })
199 + hasher.Write(buf[12:bodyend])
200 +
201 + hashed := hasher.Sum(nil)
202 + sig := buf[sigend:]
203 + switch k.Algorithm {
204 + case DSA:
205 + pk := k.publicKeyDSA()
206 + sig = sig[1:]
207 + r := big.NewInt(0)
208 + r.SetBytes(sig[:len(sig)/2])
209 + s := big.NewInt(0)
210 + s.SetBytes(sig[len(sig)/2:])
211 + if pk != nil {
212 + if dsa.Verify(pk, hashed, r, s) {
213 + return nil
214 + }
215 + return ErrSig
216 + }
217 + case RSASHA1, RSASHA256, RSASHA512:
218 + pk := k.publicKeyRSA()
219 + if pk != nil {
220 + return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
221 + }
222 + case ECDSAP256SHA256, ECDSAP384SHA384:
223 + pk := k.publicKeyECDSA()
224 + r := big.NewInt(0)
225 + r.SetBytes(sig[:len(sig)/2])
226 + s := big.NewInt(0)
227 + s.SetBytes(sig[len(sig)/2:])
228 + if pk != nil {
229 + if ecdsa.Verify(pk, hashed, r, s) {
230 + return nil
231 + }
232 + return ErrSig
233 + }
234 + }
235 + return ErrKeyAlg
236 +}
Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go new
+96
@@ -0,0 +1,96 @@
1 +package dns
2 +
3 +import (
4 + "testing"
5 + "time"
6 +)
7 +
8 +func TestSIG0(t *testing.T) {
9 + if testing.Short() {
10 + t.Skip("skipping test in short mode.")
11 + }
12 + m := new(Msg)
13 + m.SetQuestion("example.org.", TypeSOA)
14 + for _, alg := range []uint8{DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} {
15 + algstr := AlgorithmToString[alg]
16 + keyrr := new(KEY)
17 + keyrr.Hdr.Name = algstr + "."
18 + keyrr.Hdr.Rrtype = TypeKEY
19 + keyrr.Hdr.Class = ClassINET
20 + keyrr.Algorithm = alg
21 + keysize := 1024
22 + switch alg {
23 + case ECDSAP256SHA256:
24 + keysize = 256
25 + case ECDSAP384SHA384:
26 + keysize = 384
27 + }
28 + pk, err := keyrr.Generate(keysize)
29 + if err != nil {
30 + t.Logf("Failed to generate key for “%s”: %v", algstr, err)
31 + t.Fail()
32 + continue
33 + }
34 + now := uint32(time.Now().Unix())
35 + sigrr := new(SIG)
36 + sigrr.Hdr.Name = "."
37 + sigrr.Hdr.Rrtype = TypeSIG
38 + sigrr.Hdr.Class = ClassANY
39 + sigrr.Algorithm = alg
40 + sigrr.Expiration = now + 300
41 + sigrr.Inception = now - 300
42 + sigrr.KeyTag = keyrr.KeyTag()
43 + sigrr.SignerName = keyrr.Hdr.Name
44 + mb, err := sigrr.Sign(pk, m)
45 + if err != nil {
46 + t.Logf("Failed to sign message using “%s”: %v", algstr, err)
47 + t.Fail()
48 + continue
49 + }
50 + m := new(Msg)
51 + if err := m.Unpack(mb); err != nil {
52 + t.Logf("Failed to unpack message signed using “%s”: %v", algstr, err)
53 + t.Fail()
54 + continue
55 + }
56 + if len(m.Extra) != 1 {
57 + t.Logf("Missing SIG for message signed using “%s”", algstr)
58 + t.Fail()
59 + continue
60 + }
61 + var sigrrwire *SIG
62 + switch rr := m.Extra[0].(type) {
63 + case *SIG:
64 + sigrrwire = rr
65 + default:
66 + t.Logf("Expected SIG RR, instead: %v", rr)
67 + t.Fail()
68 + continue
69 + }
70 + for _, rr := range []*SIG{sigrr, sigrrwire} {
71 + id := "sigrr"
72 + if rr == sigrrwire {
73 + id = "sigrrwire"
74 + }
75 + if err := rr.Verify(keyrr, mb); err != nil {
76 + t.Logf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
77 + t.Fail()
78 + continue
79 + }
80 + }
81 + mb[13]++
82 + if err := sigrr.Verify(keyrr, mb); err == nil {
83 + t.Logf("Verify succeeded on an altered message using “%s”", algstr)
84 + t.Fail()
85 + continue
86 + }
87 + sigrr.Expiration = 2
88 + sigrr.Inception = 1
89 + mb, _ = sigrr.Sign(pk, m)
90 + if err := sigrr.Verify(keyrr, mb); err == nil {
91 + t.Logf("Verify succeeded on an expired message using “%s”", algstr)
92 + t.Fail()
93 + continue
94 + }
95 + }
96 +}
Godeps/_workspace/src/github.com/miekg/dns/singleinflight.go new
+57
@@ -0,0 +1,57 @@
1 +// Copyright 2013 The Go Authors. All rights reserved.
2 +// Use of this source code is governed by a BSD-style
3 +// license that can be found in the LICENSE file.
4 +
5 +// Adapted for dns package usage by Miek Gieben.
6 +
7 +package dns
8 +
9 +import "sync"
10 +import "time"
11 +
12 +// call is an in-flight or completed singleflight.Do call
13 +type call struct {
14 + wg sync.WaitGroup
15 + val *Msg
16 + rtt time.Duration
17 + err error
18 + dups int
19 +}
20 +
21 +// singleflight represents a class of work and forms a namespace in
22 +// which units of work can be executed with duplicate suppression.
23 +type singleflight struct {
24 + sync.Mutex // protects m
25 + m map[string]*call // lazily initialized
26 +}
27 +
28 +// Do executes and returns the results of the given function, making
29 +// sure that only one execution is in-flight for a given key at a
30 +// time. If a duplicate comes in, the duplicate caller waits for the
31 +// original to complete and receives the same results.
32 +// The return value shared indicates whether v was given to multiple callers.
33 +func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) {
34 + g.Lock()
35 + if g.m == nil {
36 + g.m = make(map[string]*call)
37 + }
38 + if c, ok := g.m[key]; ok {
39 + c.dups++
40 + g.Unlock()
41 + c.wg.Wait()
42 + return c.val, c.rtt, c.err, true
43 + }
44 + c := new(call)
45 + c.wg.Add(1)
46 + g.m[key] = c
47 + g.Unlock()
48 +
49 + c.val, c.rtt, c.err = fn()
50 + c.wg.Done()
51 +
52 + g.Lock()
53 + delete(g.m, key)
54 + g.Unlock()
55 +
56 + return c.val, c.rtt, c.err, c.dups > 0
57 +}
Godeps/_workspace/src/github.com/miekg/dns/tlsa.go new
+84
@@ -0,0 +1,84 @@
1 +package dns
2 +
3 +import (
4 + "crypto/sha256"
5 + "crypto/sha512"
6 + "crypto/x509"
7 + "encoding/hex"
8 + "errors"
9 + "io"
10 + "net"
11 + "strconv"
12 +)
13 +
14 +// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
15 +func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
16 + switch matchingType {
17 + case 0:
18 + switch selector {
19 + case 0:
20 + return hex.EncodeToString(cert.Raw), nil
21 + case 1:
22 + return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
23 + }
24 + case 1:
25 + h := sha256.New()
26 + switch selector {
27 + case 0:
28 + return hex.EncodeToString(cert.Raw), nil
29 + case 1:
30 + io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
31 + return hex.EncodeToString(h.Sum(nil)), nil
32 + }
33 + case 2:
34 + h := sha512.New()
35 + switch selector {
36 + case 0:
37 + return hex.EncodeToString(cert.Raw), nil
38 + case 1:
39 + io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
40 + return hex.EncodeToString(h.Sum(nil)), nil
41 + }
42 + }
43 + return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
44 +}
45 +
46 +// Sign creates a TLSA record from an SSL certificate.
47 +func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
48 + r.Hdr.Rrtype = TypeTLSA
49 + r.Usage = uint8(usage)
50 + r.Selector = uint8(selector)
51 + r.MatchingType = uint8(matchingType)
52 +
53 + r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
54 + if err != nil {
55 + return err
56 + }
57 + return nil
58 +}
59 +
60 +// Verify verifies a TLSA record against an SSL certificate. If it is OK
61 +// a nil error is returned.
62 +func (r *TLSA) Verify(cert *x509.Certificate) error {
63 + c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
64 + if err != nil {
65 + return err // Not also ErrSig?
66 + }
67 + if r.Certificate == c {
68 + return nil
69 + }
70 + return ErrSig // ErrSig, really?
71 +}
72 +
73 +// TLSAName returns the ownername of a TLSA resource record as per the
74 +// rules specified in RFC 6698, Section 3.
75 +func TLSAName(name, service, network string) (string, error) {
76 + if !IsFqdn(name) {
77 + return "", ErrFqdn
78 + }
79 + p, e := net.LookupPort(network, service)
80 + if e != nil {
81 + return "", e
82 + }
83 + return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil
84 +}
Godeps/_workspace/src/github.com/miekg/dns/tsig.go new
+384
@@ -0,0 +1,384 @@
1 +// TRANSACTION SIGNATURE
2 +//
3 +// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
4 +// The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
5 +//
6 +// Basic use pattern when querying with a TSIG name "axfr." (note that these key names
7 +// must be fully qualified - as they are domain names) and the base64 secret
8 +// "so6ZGir4GPAqINNh9U5c3A==":
9 +//
10 +// c := new(dns.Client)
11 +// c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
12 +// m := new(dns.Msg)
13 +// m.SetQuestion("miek.nl.", dns.TypeMX)
14 +// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
15 +// ...
16 +// // When sending the TSIG RR is calculated and filled in before sending
17 +//
18 +// When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
19 +// TSIG, this is the basic use pattern. In this example we request an AXFR for
20 +// miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
21 +// and using the server 176.58.119.54:
22 +//
23 +// t := new(dns.Transfer)
24 +// m := new(dns.Msg)
25 +// t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
26 +// m.SetAxfr("miek.nl.")
27 +// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
28 +// c, err := t.In(m, "176.58.119.54:53")
29 +// for r := range c { /* r.RR */ }
30 +//
31 +// You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
32 +// If something is not correct an error is returned.
33 +//
34 +// Basic use pattern validating and replying to a message that has TSIG set.
35 +//
36 +// server := &dns.Server{Addr: ":53", Net: "udp"}
37 +// server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
38 +// go server.ListenAndServe()
39 +// dns.HandleFunc(".", handleRequest)
40 +//
41 +// func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
42 +// m := new(Msg)
43 +// m.SetReply(r)
44 +// if r.IsTsig() {
45 +// if w.TsigStatus() == nil {
46 +// // *Msg r has an TSIG record and it was validated
47 +// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
48 +// } else {
49 +// // *Msg r has an TSIG records and it was not valided
50 +// }
51 +// }
52 +// w.WriteMsg(m)
53 +// }
54 +package dns
55 +
56 +import (
57 + "crypto/hmac"
58 + "crypto/md5"
59 + "crypto/sha1"
60 + "crypto/sha256"
61 + "crypto/sha512"
62 + "encoding/hex"
63 + "hash"
64 + "io"
65 + "strconv"
66 + "strings"
67 + "time"
68 +)
69 +
70 +// HMAC hashing codes. These are transmitted as domain names.
71 +const (
72 + HmacMD5 = "hmac-md5.sig-alg.reg.int."
73 + HmacSHA1 = "hmac-sha1."
74 + HmacSHA256 = "hmac-sha256."
75 + HmacSHA512 = "hmac-sha512."
76 +)
77 +
78 +type TSIG struct {
79 + Hdr RR_Header
80 + Algorithm string `dns:"domain-name"`
81 + TimeSigned uint64 `dns:"uint48"`
82 + Fudge uint16
83 + MACSize uint16
84 + MAC string `dns:"size-hex"`
85 + OrigId uint16
86 + Error uint16
87 + OtherLen uint16
88 + OtherData string `dns:"size-hex"`
89 +}
90 +
91 +func (rr *TSIG) Header() *RR_Header {
92 + return &rr.Hdr
93 +}
94 +
95 +// TSIG has no official presentation format, but this will suffice.
96 +
97 +func (rr *TSIG) String() string {
98 + s := "\n;; TSIG PSEUDOSECTION:\n"
99 + s += rr.Hdr.String() +
100 + " " + rr.Algorithm +
101 + " " + tsigTimeToString(rr.TimeSigned) +
102 + " " + strconv.Itoa(int(rr.Fudge)) +
103 + " " + strconv.Itoa(int(rr.MACSize)) +
104 + " " + strings.ToUpper(rr.MAC) +
105 + " " + strconv.Itoa(int(rr.OrigId)) +
106 + " " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
107 + " " + strconv.Itoa(int(rr.OtherLen)) +
108 + " " + rr.OtherData
109 + return s
110 +}
111 +
112 +func (rr *TSIG) len() int {
113 + return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
114 + 4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
115 +}
116 +
117 +func (rr *TSIG) copy() RR {
118 + return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
119 +}
120 +
121 +// The following values must be put in wireformat, so that the MAC can be calculated.
122 +// RFC 2845, section 3.4.2. TSIG Variables.
123 +type tsigWireFmt struct {
124 + // From RR_Header
125 + Name string `dns:"domain-name"`
126 + Class uint16
127 + Ttl uint32
128 + // Rdata of the TSIG
129 + Algorithm string `dns:"domain-name"`
130 + TimeSigned uint64 `dns:"uint48"`
131 + Fudge uint16
132 + // MACSize, MAC and OrigId excluded
133 + Error uint16
134 + OtherLen uint16
135 + OtherData string `dns:"size-hex"`
136 +}
137 +
138 +// If we have the MAC use this type to convert it to wiredata.
139 +// Section 3.4.3. Request MAC
140 +type macWireFmt struct {
141 + MACSize uint16
142 + MAC string `dns:"size-hex"`
143 +}
144 +
145 +// 3.3. Time values used in TSIG calculations
146 +type timerWireFmt struct {
147 + TimeSigned uint64 `dns:"uint48"`
148 + Fudge uint16
149 +}
150 +
151 +// TsigGenerate fills out the TSIG record attached to the message.
152 +// The message should contain
153 +// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
154 +// time fudge (defaults to 300 seconds) and the current time
155 +// The TSIG MAC is saved in that Tsig RR.
156 +// When TsigGenerate is called for the first time requestMAC is set to the empty string and
157 +// timersOnly is false.
158 +// If something goes wrong an error is returned, otherwise it is nil.
159 +func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
160 + if m.IsTsig() == nil {
161 + panic("dns: TSIG not last RR in additional")
162 + }
163 + // If we barf here, the caller is to blame
164 + rawsecret, err := fromBase64([]byte(secret))
165 + if err != nil {
166 + return nil, "", err
167 + }
168 +
169 + rr := m.Extra[len(m.Extra)-1].(*TSIG)
170 + m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
171 + mbuf, err := m.Pack()
172 + if err != nil {
173 + return nil, "", err
174 + }
175 + buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
176 +
177 + t := new(TSIG)
178 + var h hash.Hash
179 + switch rr.Algorithm {
180 + case HmacMD5:
181 + h = hmac.New(md5.New, []byte(rawsecret))
182 + case HmacSHA1:
183 + h = hmac.New(sha1.New, []byte(rawsecret))
184 + case HmacSHA256:
185 + h = hmac.New(sha256.New, []byte(rawsecret))
186 + case HmacSHA512:
187 + h = hmac.New(sha512.New, []byte(rawsecret))
188 + default:
189 + return nil, "", ErrKeyAlg
190 + }
191 + io.WriteString(h, string(buf))
192 + t.MAC = hex.EncodeToString(h.Sum(nil))
193 + t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
194 +
195 + t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
196 + t.Fudge = rr.Fudge
197 + t.TimeSigned = rr.TimeSigned
198 + t.Algorithm = rr.Algorithm
199 + t.OrigId = m.Id
200 +
201 + tbuf := make([]byte, t.len())
202 + if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
203 + tbuf = tbuf[:off] // reset to actual size used
204 + } else {
205 + return nil, "", err
206 + }
207 + mbuf = append(mbuf, tbuf...)
208 + rawSetExtraLen(mbuf, uint16(len(m.Extra)+1))
209 + return mbuf, t.MAC, nil
210 +}
211 +
212 +// TsigVerify verifies the TSIG on a message.
213 +// If the signature does not validate err contains the
214 +// error, otherwise it is nil.
215 +func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
216 + rawsecret, err := fromBase64([]byte(secret))
217 + if err != nil {
218 + return err
219 + }
220 + // Strip the TSIG from the incoming msg
221 + stripped, tsig, err := stripTsig(msg)
222 + if err != nil {
223 + return err
224 + }
225 +
226 + msgMAC, err := hex.DecodeString(tsig.MAC)
227 + if err != nil {
228 + return err
229 + }
230 +
231 + buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
232 +
233 + // Fudge factor works both ways. A message can arrive before it was signed because
234 + // of clock skew.
235 + now := uint64(time.Now().Unix())
236 + ti := now - tsig.TimeSigned
237 + if now < tsig.TimeSigned {
238 + ti = tsig.TimeSigned - now
239 + }
240 + if uint64(tsig.Fudge) < ti {
241 + return ErrTime
242 + }
243 +
244 + var h hash.Hash
245 + switch tsig.Algorithm {
246 + case HmacMD5:
247 + h = hmac.New(md5.New, rawsecret)
248 + case HmacSHA1:
249 + h = hmac.New(sha1.New, rawsecret)
250 + case HmacSHA256:
251 + h = hmac.New(sha256.New, rawsecret)
252 + case HmacSHA512:
253 + h = hmac.New(sha512.New, rawsecret)
254 + default:
255 + return ErrKeyAlg
256 + }
257 + h.Write(buf)
258 + if !hmac.Equal(h.Sum(nil), msgMAC) {
259 + return ErrSig
260 + }
261 + return nil
262 +}
263 +
264 +// Create a wiredata buffer for the MAC calculation.
265 +func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
266 + var buf []byte
267 + if rr.TimeSigned == 0 {
268 + rr.TimeSigned = uint64(time.Now().Unix())
269 + }
270 + if rr.Fudge == 0 {
271 + rr.Fudge = 300 // Standard (RFC) default.
272 + }
273 +
274 + if requestMAC != "" {
275 + m := new(macWireFmt)
276 + m.MACSize = uint16(len(requestMAC) / 2)
277 + m.MAC = requestMAC
278 + buf = make([]byte, len(requestMAC)) // long enough
279 + n, _ := PackStruct(m, buf, 0)
280 + buf = buf[:n]
281 + }
282 +
283 + tsigvar := make([]byte, DefaultMsgSize)
284 + if timersOnly {
285 + tsig := new(timerWireFmt)
286 + tsig.TimeSigned = rr.TimeSigned
287 + tsig.Fudge = rr.Fudge
288 + n, _ := PackStruct(tsig, tsigvar, 0)
289 + tsigvar = tsigvar[:n]
290 + } else {
291 + tsig := new(tsigWireFmt)
292 + tsig.Name = strings.ToLower(rr.Hdr.Name)
293 + tsig.Class = ClassANY
294 + tsig.Ttl = rr.Hdr.Ttl
295 + tsig.Algorithm = strings.ToLower(rr.Algorithm)
296 + tsig.TimeSigned = rr.TimeSigned
297 + tsig.Fudge = rr.Fudge
298 + tsig.Error = rr.Error
299 + tsig.OtherLen = rr.OtherLen
300 + tsig.OtherData = rr.OtherData
301 + n, _ := PackStruct(tsig, tsigvar, 0)
302 + tsigvar = tsigvar[:n]
303 + }
304 +
305 + if requestMAC != "" {
306 + x := append(buf, msgbuf...)
307 + buf = append(x, tsigvar...)
308 + } else {
309 + buf = append(msgbuf, tsigvar...)
310 + }
311 + return buf
312 +}
313 +
314 +// Strip the TSIG from the raw message.
315 +func stripTsig(msg []byte) ([]byte, *TSIG, error) {
316 + // Copied from msg.go's Unpack()
317 + // Header.
318 + var dh Header
319 + var err error
320 + dns := new(Msg)
321 + rr := new(TSIG)
322 + off := 0
323 + tsigoff := 0
324 + if off, err = UnpackStruct(&dh, msg, off); err != nil {
325 + return nil, nil, err
326 + }
327 + if dh.Arcount == 0 {
328 + return nil, nil, ErrNoSig
329 + }
330 + // Rcode, see msg.go Unpack()
331 + if int(dh.Bits&0xF) == RcodeNotAuth {
332 + return nil, nil, ErrAuth
333 + }
334 +
335 + // Arrays.
336 + dns.Question = make([]Question, dh.Qdcount)
337 + dns.Answer = make([]RR, dh.Ancount)
338 + dns.Ns = make([]RR, dh.Nscount)
339 + dns.Extra = make([]RR, dh.Arcount)
340 +
341 + for i := 0; i < len(dns.Question); i++ {
342 + off, err = UnpackStruct(&dns.Question[i], msg, off)
343 + if err != nil {
344 + return nil, nil, err
345 + }
346 + }
347 + for i := 0; i < len(dns.Answer); i++ {
348 + dns.Answer[i], off, err = UnpackRR(msg, off)
349 + if err != nil {
350 + return nil, nil, err
351 + }
352 + }
353 + for i := 0; i < len(dns.Ns); i++ {
354 + dns.Ns[i], off, err = UnpackRR(msg, off)
355 + if err != nil {
356 + return nil, nil, err
357 + }
358 + }
359 + for i := 0; i < len(dns.Extra); i++ {
360 + tsigoff = off
361 + dns.Extra[i], off, err = UnpackRR(msg, off)
362 + if err != nil {
363 + return nil, nil, err
364 + }
365 + if dns.Extra[i].Header().Rrtype == TypeTSIG {
366 + rr = dns.Extra[i].(*TSIG)
367 + // Adjust Arcount.
368 + arcount, _ := unpackUint16(msg, 10)
369 + msg[10], msg[11] = packUint16(arcount - 1)
370 + break
371 + }
372 + }
373 + if rr == nil {
374 + return nil, nil, ErrNoSig
375 + }
376 + return msg[:tsigoff], rr, nil
377 +}
378 +
379 +// Translate the TSIG time signed into a date. There is no
380 +// need for RFC1982 calculations as this date is 48 bits.
381 +func tsigTimeToString(t uint64) string {
382 + ti := time.Unix(int64(t), 0).UTC()
383 + return ti.Format("20060102150405")
384 +}
Godeps/_workspace/src/github.com/miekg/dns/types.go new
+1728
@@ -0,0 +1,1728 @@
1 +package dns
2 +
3 +import (
4 + "encoding/base64"
5 + "fmt"
6 + "net"
7 + "strconv"
8 + "strings"
9 + "time"
10 +)
11 +
12 +type (
13 + Type uint16 // Type is a DNS type.
14 + Class uint16 // Class is a DNS class.
15 + Name string // Name is a DNS domain name.
16 +)
17 +
18 +// Packet formats
19 +
20 +// Wire constants and supported types.
21 +const (
22 + // valid RR_Header.Rrtype and Question.qtype
23 + TypeNone uint16 = 0
24 + TypeA uint16 = 1
25 + TypeNS uint16 = 2
26 + TypeMD uint16 = 3
27 + TypeMF uint16 = 4
28 + TypeCNAME uint16 = 5
29 + TypeSOA uint16 = 6
30 + TypeMB uint16 = 7
31 + TypeMG uint16 = 8
32 + TypeMR uint16 = 9
33 + TypeNULL uint16 = 10
34 + TypeWKS uint16 = 11
35 + TypePTR uint16 = 12
36 + TypeHINFO uint16 = 13
37 + TypeMINFO uint16 = 14
38 + TypeMX uint16 = 15
39 + TypeTXT uint16 = 16
40 + TypeRP uint16 = 17
41 + TypeAFSDB uint16 = 18
42 + TypeX25 uint16 = 19
43 + TypeISDN uint16 = 20
44 + TypeRT uint16 = 21
45 + TypeNSAP uint16 = 22
46 + TypeNSAPPTR uint16 = 23
47 + TypeSIG uint16 = 24
48 + TypeKEY uint16 = 25
49 + TypePX uint16 = 26
50 + TypeGPOS uint16 = 27
51 + TypeAAAA uint16 = 28
52 + TypeLOC uint16 = 29
53 + TypeNXT uint16 = 30
54 + TypeEID uint16 = 31
55 + TypeNIMLOC uint16 = 32
56 + TypeSRV uint16 = 33
57 + TypeATMA uint16 = 34
58 + TypeNAPTR uint16 = 35
59 + TypeKX uint16 = 36
60 + TypeCERT uint16 = 37
61 + TypeDNAME uint16 = 39
62 + TypeOPT uint16 = 41 // EDNS
63 + TypeDS uint16 = 43
64 + TypeSSHFP uint16 = 44
65 + TypeIPSECKEY uint16 = 45
66 + TypeRRSIG uint16 = 46
67 + TypeNSEC uint16 = 47
68 + TypeDNSKEY uint16 = 48
69 + TypeDHCID uint16 = 49
70 + TypeNSEC3 uint16 = 50
71 + TypeNSEC3PARAM uint16 = 51
72 + TypeTLSA uint16 = 52
73 + TypeHIP uint16 = 55
74 + TypeNINFO uint16 = 56
75 + TypeRKEY uint16 = 57
76 + TypeTALINK uint16 = 58
77 + TypeCDS uint16 = 59
78 + TypeCDNSKEY uint16 = 60
79 + TypeOPENPGPKEY uint16 = 61
80 + TypeSPF uint16 = 99
81 + TypeUINFO uint16 = 100
82 + TypeUID uint16 = 101
83 + TypeGID uint16 = 102
84 + TypeUNSPEC uint16 = 103
85 + TypeNID uint16 = 104
86 + TypeL32 uint16 = 105
87 + TypeL64 uint16 = 106
88 + TypeLP uint16 = 107
89 + TypeEUI48 uint16 = 108
90 + TypeEUI64 uint16 = 109
91 +
92 + TypeTKEY uint16 = 249
93 + TypeTSIG uint16 = 250
94 + // valid Question.Qtype only
95 + TypeIXFR uint16 = 251
96 + TypeAXFR uint16 = 252
97 + TypeMAILB uint16 = 253
98 + TypeMAILA uint16 = 254
99 + TypeANY uint16 = 255
100 +
101 + TypeURI uint16 = 256
102 + TypeCAA uint16 = 257
103 + TypeTA uint16 = 32768
104 + TypeDLV uint16 = 32769
105 + TypeReserved uint16 = 65535
106 +
107 + // valid Question.Qclass
108 + ClassINET = 1
109 + ClassCSNET = 2
110 + ClassCHAOS = 3
111 + ClassHESIOD = 4
112 + ClassNONE = 254
113 + ClassANY = 255
114 +
115 + // Msg.rcode
116 + RcodeSuccess = 0
117 + RcodeFormatError = 1
118 + RcodeServerFailure = 2
119 + RcodeNameError = 3
120 + RcodeNotImplemented = 4
121 + RcodeRefused = 5
122 + RcodeYXDomain = 6
123 + RcodeYXRrset = 7
124 + RcodeNXRrset = 8
125 + RcodeNotAuth = 9
126 + RcodeNotZone = 10
127 + RcodeBadSig = 16 // TSIG
128 + RcodeBadVers = 16 // EDNS0
129 + RcodeBadKey = 17
130 + RcodeBadTime = 18
131 + RcodeBadMode = 19 // TKEY
132 + RcodeBadName = 20
133 + RcodeBadAlg = 21
134 + RcodeBadTrunc = 22 // TSIG
135 +
136 + // Opcode
137 + OpcodeQuery = 0
138 + OpcodeIQuery = 1
139 + OpcodeStatus = 2
140 + // There is no 3
141 + OpcodeNotify = 4
142 + OpcodeUpdate = 5
143 +)
144 +
145 +// The wire format for the DNS packet header.
146 +type Header struct {
147 + Id uint16
148 + Bits uint16
149 + Qdcount, Ancount, Nscount, Arcount uint16
150 +}
151 +
152 +const (
153 + // Header.Bits
154 + _QR = 1 << 15 // query/response (response=1)
155 + _AA = 1 << 10 // authoritative
156 + _TC = 1 << 9 // truncated
157 + _RD = 1 << 8 // recursion desired
158 + _RA = 1 << 7 // recursion available
159 + _Z = 1 << 6 // Z
160 + _AD = 1 << 5 // authticated data
161 + _CD = 1 << 4 // checking disabled
162 +
163 + LOC_EQUATOR = 1 << 31 // RFC 1876, Section 2.
164 + LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2.
165 +
166 + LOC_HOURS = 60 * 1000
167 + LOC_DEGREES = 60 * LOC_HOURS
168 +
169 + LOC_ALTITUDEBASE = 100000
170 +)
171 +
172 +// RFC 4398, Section 2.1
173 +const (
174 + CertPKIX = 1 + iota
175 + CertSPKI
176 + CertPGP
177 + CertIPIX
178 + CertISPKI
179 + CertIPGP
180 + CertACPKIX
181 + CertIACPKIX
182 + CertURI = 253
183 + CertOID = 254
184 +)
185 +
186 +var CertTypeToString = map[uint16]string{
187 + CertPKIX: "PKIX",
188 + CertSPKI: "SPKI",
189 + CertPGP: "PGP",
190 + CertIPIX: "IPIX",
191 + CertISPKI: "ISPKI",
192 + CertIPGP: "IPGP",
193 + CertACPKIX: "ACPKIX",
194 + CertIACPKIX: "IACPKIX",
195 + CertURI: "URI",
196 + CertOID: "OID",
197 +}
198 +
199 +var StringToCertType = reverseInt16(CertTypeToString)
200 +
201 +// DNS queries.
202 +type Question struct {
203 + Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed)
204 + Qtype uint16
205 + Qclass uint16
206 +}
207 +
208 +func (q *Question) String() (s string) {
209 + // prefix with ; (as in dig)
210 + s = ";" + sprintName(q.Name) + "\t"
211 + s += Class(q.Qclass).String() + "\t"
212 + s += " " + Type(q.Qtype).String()
213 + return s
214 +}
215 +
216 +func (q *Question) len() int {
217 + l := len(q.Name) + 1
218 + return l + 4
219 +}
220 +
221 +type ANY struct {
222 + Hdr RR_Header
223 + // Does not have any rdata
224 +}
225 +
226 +func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
227 +func (rr *ANY) copy() RR { return &ANY{*rr.Hdr.copyHeader()} }
228 +func (rr *ANY) String() string { return rr.Hdr.String() }
229 +func (rr *ANY) len() int { return rr.Hdr.len() }
230 +
231 +type CNAME struct {
232 + Hdr RR_Header
233 + Target string `dns:"cdomain-name"`
234 +}
235 +
236 +func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
237 +func (rr *CNAME) copy() RR { return &CNAME{*rr.Hdr.copyHeader(), sprintName(rr.Target)} }
238 +func (rr *CNAME) String() string { return rr.Hdr.String() + rr.Target }
239 +func (rr *CNAME) len() int { return rr.Hdr.len() + len(rr.Target) + 1 }
240 +
241 +type HINFO struct {
242 + Hdr RR_Header
243 + Cpu string
244 + Os string
245 +}
246 +
247 +func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
248 +func (rr *HINFO) copy() RR { return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} }
249 +func (rr *HINFO) String() string { return rr.Hdr.String() + rr.Cpu + " " + rr.Os }
250 +func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) }
251 +
252 +type MB struct {
253 + Hdr RR_Header
254 + Mb string `dns:"cdomain-name"`
255 +}
256 +
257 +func (rr *MB) Header() *RR_Header { return &rr.Hdr }
258 +func (rr *MB) copy() RR { return &MB{*rr.Hdr.copyHeader(), sprintName(rr.Mb)} }
259 +
260 +func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb }
261 +func (rr *MB) len() int { return rr.Hdr.len() + len(rr.Mb) + 1 }
262 +
263 +type MG struct {
264 + Hdr RR_Header
265 + Mg string `dns:"cdomain-name"`
266 +}
267 +
268 +func (rr *MG) Header() *RR_Header { return &rr.Hdr }
269 +func (rr *MG) copy() RR { return &MG{*rr.Hdr.copyHeader(), rr.Mg} }
270 +func (rr *MG) len() int { l := len(rr.Mg) + 1; return rr.Hdr.len() + l }
271 +func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
272 +
273 +type MINFO struct {
274 + Hdr RR_Header
275 + Rmail string `dns:"cdomain-name"`
276 + Email string `dns:"cdomain-name"`
277 +}
278 +
279 +func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
280 +func (rr *MINFO) copy() RR { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} }
281 +
282 +func (rr *MINFO) String() string {
283 + return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
284 +}
285 +
286 +func (rr *MINFO) len() int {
287 + l := len(rr.Rmail) + 1
288 + n := len(rr.Email) + 1
289 + return rr.Hdr.len() + l + n
290 +}
291 +
292 +type MR struct {
293 + Hdr RR_Header
294 + Mr string `dns:"cdomain-name"`
295 +}
296 +
297 +func (rr *MR) Header() *RR_Header { return &rr.Hdr }
298 +func (rr *MR) copy() RR { return &MR{*rr.Hdr.copyHeader(), rr.Mr} }
299 +func (rr *MR) len() int { l := len(rr.Mr) + 1; return rr.Hdr.len() + l }
300 +
301 +func (rr *MR) String() string {
302 + return rr.Hdr.String() + sprintName(rr.Mr)
303 +}
304 +
305 +type MF struct {
306 + Hdr RR_Header
307 + Mf string `dns:"cdomain-name"`
308 +}
309 +
310 +func (rr *MF) Header() *RR_Header { return &rr.Hdr }
311 +func (rr *MF) copy() RR { return &MF{*rr.Hdr.copyHeader(), rr.Mf} }
312 +func (rr *MF) len() int { return rr.Hdr.len() + len(rr.Mf) + 1 }
313 +
314 +func (rr *MF) String() string {
315 + return rr.Hdr.String() + sprintName(rr.Mf)
316 +}
317 +
318 +type MD struct {
319 + Hdr RR_Header
320 + Md string `dns:"cdomain-name"`
321 +}
322 +
323 +func (rr *MD) Header() *RR_Header { return &rr.Hdr }
324 +func (rr *MD) copy() RR { return &MD{*rr.Hdr.copyHeader(), rr.Md} }
325 +func (rr *MD) len() int { return rr.Hdr.len() + len(rr.Md) + 1 }
326 +
327 +func (rr *MD) String() string {
328 + return rr.Hdr.String() + sprintName(rr.Md)
329 +}
330 +
331 +type MX struct {
332 + Hdr RR_Header
333 + Preference uint16
334 + Mx string `dns:"cdomain-name"`
335 +}
336 +
337 +func (rr *MX) Header() *RR_Header { return &rr.Hdr }
338 +func (rr *MX) copy() RR { return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} }
339 +func (rr *MX) len() int { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 }
340 +
341 +func (rr *MX) String() string {
342 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
343 +}
344 +
345 +type AFSDB struct {
346 + Hdr RR_Header
347 + Subtype uint16
348 + Hostname string `dns:"cdomain-name"`
349 +}
350 +
351 +func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
352 +func (rr *AFSDB) copy() RR { return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} }
353 +func (rr *AFSDB) len() int { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 }
354 +
355 +func (rr *AFSDB) String() string {
356 + return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
357 +}
358 +
359 +type X25 struct {
360 + Hdr RR_Header
361 + PSDNAddress string
362 +}
363 +
364 +func (rr *X25) Header() *RR_Header { return &rr.Hdr }
365 +func (rr *X25) copy() RR { return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} }
366 +func (rr *X25) len() int { return rr.Hdr.len() + len(rr.PSDNAddress) + 1 }
367 +
368 +func (rr *X25) String() string {
369 + return rr.Hdr.String() + rr.PSDNAddress
370 +}
371 +
372 +type RT struct {
373 + Hdr RR_Header
374 + Preference uint16
375 + Host string `dns:"cdomain-name"`
376 +}
377 +
378 +func (rr *RT) Header() *RR_Header { return &rr.Hdr }
379 +func (rr *RT) copy() RR { return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} }
380 +func (rr *RT) len() int { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 }
381 +
382 +func (rr *RT) String() string {
383 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
384 +}
385 +
386 +type NS struct {
387 + Hdr RR_Header
388 + Ns string `dns:"cdomain-name"`
389 +}
390 +
391 +func (rr *NS) Header() *RR_Header { return &rr.Hdr }
392 +func (rr *NS) len() int { l := len(rr.Ns) + 1; return rr.Hdr.len() + l }
393 +func (rr *NS) copy() RR { return &NS{*rr.Hdr.copyHeader(), rr.Ns} }
394 +
395 +func (rr *NS) String() string {
396 + return rr.Hdr.String() + sprintName(rr.Ns)
397 +}
398 +
399 +type PTR struct {
400 + Hdr RR_Header
401 + Ptr string `dns:"cdomain-name"`
402 +}
403 +
404 +func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
405 +func (rr *PTR) copy() RR { return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} }
406 +func (rr *PTR) len() int { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l }
407 +
408 +func (rr *PTR) String() string {
409 + return rr.Hdr.String() + sprintName(rr.Ptr)
410 +}
411 +
412 +type RP struct {
413 + Hdr RR_Header
414 + Mbox string `dns:"domain-name"`
415 + Txt string `dns:"domain-name"`
416 +}
417 +
418 +func (rr *RP) Header() *RR_Header { return &rr.Hdr }
419 +func (rr *RP) copy() RR { return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} }
420 +func (rr *RP) len() int { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 }
421 +
422 +func (rr *RP) String() string {
423 + return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
424 +}
425 +
426 +type SOA struct {
427 + Hdr RR_Header
428 + Ns string `dns:"cdomain-name"`
429 + Mbox string `dns:"cdomain-name"`
430 + Serial uint32
431 + Refresh uint32
432 + Retry uint32
433 + Expire uint32
434 + Minttl uint32
435 +}
436 +
437 +func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
438 +func (rr *SOA) copy() RR {
439 + return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
440 +}
441 +
442 +func (rr *SOA) String() string {
443 + return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
444 + " " + strconv.FormatInt(int64(rr.Serial), 10) +
445 + " " + strconv.FormatInt(int64(rr.Refresh), 10) +
446 + " " + strconv.FormatInt(int64(rr.Retry), 10) +
447 + " " + strconv.FormatInt(int64(rr.Expire), 10) +
448 + " " + strconv.FormatInt(int64(rr.Minttl), 10)
449 +}
450 +
451 +func (rr *SOA) len() int {
452 + l := len(rr.Ns) + 1
453 + n := len(rr.Mbox) + 1
454 + return rr.Hdr.len() + l + n + 20
455 +}
456 +
457 +type TXT struct {
458 + Hdr RR_Header
459 + Txt []string `dns:"txt"`
460 +}
461 +
462 +func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
463 +func (rr *TXT) copy() RR {
464 + cp := make([]string, len(rr.Txt), cap(rr.Txt))
465 + copy(cp, rr.Txt)
466 + return &TXT{*rr.Hdr.copyHeader(), cp}
467 +}
468 +
469 +func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
470 +
471 +func sprintName(s string) string {
472 + src := []byte(s)
473 + dst := make([]byte, 0, len(src))
474 + for i := 0; i < len(src); {
475 + if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' {
476 + dst = append(dst, src[i:i+2]...)
477 + i += 2
478 + } else {
479 + b, n := nextByte(src, i)
480 + if n == 0 {
481 + i++ // dangling back slash
482 + } else if b == '.' {
483 + dst = append(dst, b)
484 + } else {
485 + dst = appendDomainNameByte(dst, b)
486 + }
487 + i += n
488 + }
489 + }
490 + return string(dst)
491 +}
492 +
493 +func sprintTxt(txt []string) string {
494 + var out []byte
495 + for i, s := range txt {
496 + if i > 0 {
497 + out = append(out, ` "`...)
498 + } else {
499 + out = append(out, '"')
500 + }
501 + bs := []byte(s)
502 + for j := 0; j < len(bs); {
503 + b, n := nextByte(bs, j)
504 + if n == 0 {
505 + break
506 + }
507 + out = appendTXTStringByte(out, b)
508 + j += n
509 + }
510 + out = append(out, '"')
511 + }
512 + return string(out)
513 +}
514 +
515 +func appendDomainNameByte(s []byte, b byte) []byte {
516 + switch b {
517 + case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
518 + return append(s, '\\', b)
519 + }
520 + return appendTXTStringByte(s, b)
521 +}
522 +
523 +func appendTXTStringByte(s []byte, b byte) []byte {
524 + switch b {
525 + case '\t':
526 + return append(s, '\\', 't')
527 + case '\r':
528 + return append(s, '\\', 'r')
529 + case '\n':
530 + return append(s, '\\', 'n')
531 + case '"', '\\':
532 + return append(s, '\\', b)
533 + }
534 + if b < ' ' || b > '~' {
535 + var buf [3]byte
536 + bufs := strconv.AppendInt(buf[:0], int64(b), 10)
537 + s = append(s, '\\')
538 + for i := 0; i < 3-len(bufs); i++ {
539 + s = append(s, '0')
540 + }
541 + for _, r := range bufs {
542 + s = append(s, r)
543 + }
544 + return s
545 +
546 + }
547 + return append(s, b)
548 +}
549 +
550 +func nextByte(b []byte, offset int) (byte, int) {
551 + if offset >= len(b) {
552 + return 0, 0
553 + }
554 + if b[offset] != '\\' {
555 + // not an escape sequence
556 + return b[offset], 1
557 + }
558 + switch len(b) - offset {
559 + case 1: // dangling escape
560 + return 0, 0
561 + case 2, 3: // too short to be \ddd
562 + default: // maybe \ddd
563 + if isDigit(b[offset+1]) && isDigit(b[offset+2]) && isDigit(b[offset+3]) {
564 + return dddToByte(b[offset+1:]), 4
565 + }
566 + }
567 + // not \ddd, maybe a control char
568 + switch b[offset+1] {
569 + case 't':
570 + return '\t', 2
571 + case 'r':
572 + return '\r', 2
573 + case 'n':
574 + return '\n', 2
575 + default:
576 + return b[offset+1], 2
577 + }
578 +}
579 +
580 +func (rr *TXT) len() int {
581 + l := rr.Hdr.len()
582 + for _, t := range rr.Txt {
583 + l += len(t) + 1
584 + }
585 + return l
586 +}
587 +
588 +type SPF struct {
589 + Hdr RR_Header
590 + Txt []string `dns:"txt"`
591 +}
592 +
593 +func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
594 +func (rr *SPF) copy() RR {
595 + cp := make([]string, len(rr.Txt), cap(rr.Txt))
596 + copy(cp, rr.Txt)
597 + return &SPF{*rr.Hdr.copyHeader(), cp}
598 +}
599 +
600 +func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
601 +
602 +func (rr *SPF) len() int {
603 + l := rr.Hdr.len()
604 + for _, t := range rr.Txt {
605 + l += len(t) + 1
606 + }
607 + return l
608 +}
609 +
610 +type SRV struct {
611 + Hdr RR_Header
612 + Priority uint16
613 + Weight uint16
614 + Port uint16
615 + Target string `dns:"domain-name"`
616 +}
617 +
618 +func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
619 +func (rr *SRV) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l + 6 }
620 +func (rr *SRV) copy() RR {
621 + return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
622 +}
623 +
624 +func (rr *SRV) String() string {
625 + return rr.Hdr.String() +
626 + strconv.Itoa(int(rr.Priority)) + " " +
627 + strconv.Itoa(int(rr.Weight)) + " " +
628 + strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target)
629 +}
630 +
631 +type NAPTR struct {
632 + Hdr RR_Header
633 + Order uint16
634 + Preference uint16
635 + Flags string
636 + Service string
637 + Regexp string
638 + Replacement string `dns:"domain-name"`
639 +}
640 +
641 +func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
642 +func (rr *NAPTR) copy() RR {
643 + return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
644 +}
645 +
646 +func (rr *NAPTR) String() string {
647 + return rr.Hdr.String() +
648 + strconv.Itoa(int(rr.Order)) + " " +
649 + strconv.Itoa(int(rr.Preference)) + " " +
650 + "\"" + rr.Flags + "\" " +
651 + "\"" + rr.Service + "\" " +
652 + "\"" + rr.Regexp + "\" " +
653 + rr.Replacement
654 +}
655 +
656 +func (rr *NAPTR) len() int {
657 + return rr.Hdr.len() + 4 + len(rr.Flags) + 1 + len(rr.Service) + 1 +
658 + len(rr.Regexp) + 1 + len(rr.Replacement) + 1
659 +}
660 +
661 +// See RFC 4398.
662 +type CERT struct {
663 + Hdr RR_Header
664 + Type uint16
665 + KeyTag uint16
666 + Algorithm uint8
667 + Certificate string `dns:"base64"`
668 +}
669 +
670 +func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
671 +func (rr *CERT) copy() RR {
672 + return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
673 +}
674 +
675 +func (rr *CERT) String() string {
676 + var (
677 + ok bool
678 + certtype, algorithm string
679 + )
680 + if certtype, ok = CertTypeToString[rr.Type]; !ok {
681 + certtype = strconv.Itoa(int(rr.Type))
682 + }
683 + if algorithm, ok = AlgorithmToString[rr.Algorithm]; !ok {
684 + algorithm = strconv.Itoa(int(rr.Algorithm))
685 + }
686 + return rr.Hdr.String() + certtype +
687 + " " + strconv.Itoa(int(rr.KeyTag)) +
688 + " " + algorithm +
689 + " " + rr.Certificate
690 +}
691 +
692 +func (rr *CERT) len() int {
693 + return rr.Hdr.len() + 5 +
694 + base64.StdEncoding.DecodedLen(len(rr.Certificate))
695 +}
696 +
697 +// See RFC 2672.
698 +type DNAME struct {
699 + Hdr RR_Header
700 + Target string `dns:"domain-name"`
701 +}
702 +
703 +func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
704 +func (rr *DNAME) copy() RR { return &DNAME{*rr.Hdr.copyHeader(), rr.Target} }
705 +func (rr *DNAME) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l }
706 +
707 +func (rr *DNAME) String() string {
708 + return rr.Hdr.String() + sprintName(rr.Target)
709 +}
710 +
711 +type A struct {
712 + Hdr RR_Header
713 + A net.IP `dns:"a"`
714 +}
715 +
716 +func (rr *A) Header() *RR_Header { return &rr.Hdr }
717 +func (rr *A) copy() RR { return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} }
718 +func (rr *A) len() int { return rr.Hdr.len() + net.IPv4len }
719 +
720 +func (rr *A) String() string {
721 + if rr.A == nil {
722 + return rr.Hdr.String()
723 + }
724 + return rr.Hdr.String() + rr.A.String()
725 +}
726 +
727 +type AAAA struct {
728 + Hdr RR_Header
729 + AAAA net.IP `dns:"aaaa"`
730 +}
731 +
732 +func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
733 +func (rr *AAAA) copy() RR { return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} }
734 +func (rr *AAAA) len() int { return rr.Hdr.len() + net.IPv6len }
735 +
736 +func (rr *AAAA) String() string {
737 + if rr.AAAA == nil {
738 + return rr.Hdr.String()
739 + }
740 + return rr.Hdr.String() + rr.AAAA.String()
741 +}
742 +
743 +type PX struct {
744 + Hdr RR_Header
745 + Preference uint16
746 + Map822 string `dns:"domain-name"`
747 + Mapx400 string `dns:"domain-name"`
748 +}
749 +
750 +func (rr *PX) Header() *RR_Header { return &rr.Hdr }
751 +func (rr *PX) copy() RR { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} }
752 +func (rr *PX) String() string {
753 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
754 +}
755 +func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 }
756 +
757 +type GPOS struct {
758 + Hdr RR_Header
759 + Longitude string
760 + Latitude string
761 + Altitude string
762 +}
763 +
764 +func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
765 +func (rr *GPOS) copy() RR { return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} }
766 +func (rr *GPOS) len() int {
767 + return rr.Hdr.len() + len(rr.Longitude) + len(rr.Latitude) + len(rr.Altitude) + 3
768 +}
769 +func (rr *GPOS) String() string {
770 + return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
771 +}
772 +
773 +type LOC struct {
774 + Hdr RR_Header
775 + Version uint8
776 + Size uint8
777 + HorizPre uint8
778 + VertPre uint8
779 + Latitude uint32
780 + Longitude uint32
781 + Altitude uint32
782 +}
783 +
784 +func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
785 +func (rr *LOC) len() int { return rr.Hdr.len() + 4 + 12 }
786 +func (rr *LOC) copy() RR {
787 + return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
788 +}
789 +
790 +// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent
791 +// format and returns a string in m (two decimals for the cm)
792 +func cmToM(m, e uint8) string {
793 + if e < 2 {
794 + if e == 1 {
795 + m *= 10
796 + }
797 +
798 + return fmt.Sprintf("0.%02d", m)
799 + }
800 +
801 + s := fmt.Sprintf("%d", m)
802 + for e > 2 {
803 + s += "0"
804 + e -= 1
805 + }
806 + return s
807 +}
808 +
809 +// String returns a string version of a LOC
810 +func (rr *LOC) String() string {
811 + s := rr.Hdr.String()
812 +
813 + lat := rr.Latitude
814 + ns := "N"
815 + if lat > LOC_EQUATOR {
816 + lat = lat - LOC_EQUATOR
817 + } else {
818 + ns = "S"
819 + lat = LOC_EQUATOR - lat
820 + }
821 + h := lat / LOC_DEGREES
822 + lat = lat % LOC_DEGREES
823 + m := lat / LOC_HOURS
824 + lat = lat % LOC_HOURS
825 + s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lat) / 1000), ns)
826 +
827 + lon := rr.Longitude
828 + ew := "E"
829 + if lon > LOC_PRIMEMERIDIAN {
830 + lon = lon - LOC_PRIMEMERIDIAN
831 + } else {
832 + ew = "W"
833 + lon = LOC_PRIMEMERIDIAN - lon
834 + }
835 + h = lon / LOC_DEGREES
836 + lon = lon % LOC_DEGREES
837 + m = lon / LOC_HOURS
838 + lon = lon % LOC_HOURS
839 + s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lon) / 1000), ew)
840 +
841 + var alt float64 = float64(rr.Altitude) / 100
842 + alt -= LOC_ALTITUDEBASE
843 + if rr.Altitude%100 != 0 {
844 + s += fmt.Sprintf("%.2fm ", alt)
845 + } else {
846 + s += fmt.Sprintf("%.0fm ", alt)
847 + }
848 +
849 + s += cmToM((rr.Size&0xf0)>>4, rr.Size&0x0f) + "m "
850 + s += cmToM((rr.HorizPre&0xf0)>>4, rr.HorizPre&0x0f) + "m "
851 + s += cmToM((rr.VertPre&0xf0)>>4, rr.VertPre&0x0f) + "m"
852 +
853 + return s
854 +}
855 +
856 +// SIG is identical to RRSIG and nowadays only used for SIG(0), RFC2931.
857 +type SIG struct {
858 + RRSIG
859 +}
860 +
861 +type RRSIG struct {
862 + Hdr RR_Header
863 + TypeCovered uint16
864 + Algorithm uint8
865 + Labels uint8
866 + OrigTtl uint32
867 + Expiration uint32
868 + Inception uint32
869 + KeyTag uint16
870 + SignerName string `dns:"domain-name"`
871 + Signature string `dns:"base64"`
872 +}
873 +
874 +func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
875 +func (rr *RRSIG) copy() RR {
876 + return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
877 +}
878 +
879 +func (rr *RRSIG) String() string {
880 + s := rr.Hdr.String()
881 + s += Type(rr.TypeCovered).String()
882 + s += " " + strconv.Itoa(int(rr.Algorithm)) +
883 + " " + strconv.Itoa(int(rr.Labels)) +
884 + " " + strconv.FormatInt(int64(rr.OrigTtl), 10) +
885 + " " + TimeToString(rr.Expiration) +
886 + " " + TimeToString(rr.Inception) +
887 + " " + strconv.Itoa(int(rr.KeyTag)) +
888 + " " + sprintName(rr.SignerName) +
889 + " " + rr.Signature
890 + return s
891 +}
892 +
893 +func (rr *RRSIG) len() int {
894 + return rr.Hdr.len() + len(rr.SignerName) + 1 +
895 + base64.StdEncoding.DecodedLen(len(rr.Signature)) + 18
896 +}
897 +
898 +type NSEC struct {
899 + Hdr RR_Header
900 + NextDomain string `dns:"domain-name"`
901 + TypeBitMap []uint16 `dns:"nsec"`
902 +}
903 +
904 +func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
905 +func (rr *NSEC) copy() RR {
906 + cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap))
907 + copy(cp, rr.TypeBitMap)
908 + return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, cp}
909 +}
910 +
911 +func (rr *NSEC) String() string {
912 + s := rr.Hdr.String() + sprintName(rr.NextDomain)
913 + for i := 0; i < len(rr.TypeBitMap); i++ {
914 + s += " " + Type(rr.TypeBitMap[i]).String()
915 + }
916 + return s
917 +}
918 +
919 +func (rr *NSEC) len() int {
920 + l := rr.Hdr.len() + len(rr.NextDomain) + 1
921 + lastwindow := uint32(2 ^ 32 + 1)
922 + for _, t := range rr.TypeBitMap {
923 + window := t / 256
924 + if uint32(window) != lastwindow {
925 + l += 1 + 32
926 + }
927 + lastwindow = uint32(window)
928 + }
929 + return l
930 +}
931 +
932 +type DLV struct {
933 + DS
934 +}
935 +
936 +type CDS struct {
937 + DS
938 +}
939 +
940 +type DS struct {
941 + Hdr RR_Header
942 + KeyTag uint16
943 + Algorithm uint8
944 + DigestType uint8
945 + Digest string `dns:"hex"`
946 +}
947 +
948 +func (rr *DS) Header() *RR_Header { return &rr.Hdr }
949 +func (rr *DS) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 }
950 +func (rr *DS) copy() RR {
951 + return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
952 +}
953 +
954 +func (rr *DS) String() string {
955 + return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
956 + " " + strconv.Itoa(int(rr.Algorithm)) +
957 + " " + strconv.Itoa(int(rr.DigestType)) +
958 + " " + strings.ToUpper(rr.Digest)
959 +}
960 +
961 +type KX struct {
962 + Hdr RR_Header
963 + Preference uint16
964 + Exchanger string `dns:"domain-name"`
965 +}
966 +
967 +func (rr *KX) Header() *RR_Header { return &rr.Hdr }
968 +func (rr *KX) len() int { return rr.Hdr.len() + 2 + len(rr.Exchanger) + 1 }
969 +func (rr *KX) copy() RR { return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} }
970 +
971 +func (rr *KX) String() string {
972 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
973 + " " + sprintName(rr.Exchanger)
974 +}
975 +
976 +type TA struct {
977 + Hdr RR_Header
978 + KeyTag uint16
979 + Algorithm uint8
980 + DigestType uint8
981 + Digest string `dns:"hex"`
982 +}
983 +
984 +func (rr *TA) Header() *RR_Header { return &rr.Hdr }
985 +func (rr *TA) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 }
986 +func (rr *TA) copy() RR {
987 + return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
988 +}
989 +
990 +func (rr *TA) String() string {
991 + return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
992 + " " + strconv.Itoa(int(rr.Algorithm)) +
993 + " " + strconv.Itoa(int(rr.DigestType)) +
994 + " " + strings.ToUpper(rr.Digest)
995 +}
996 +
997 +type TALINK struct {
998 + Hdr RR_Header
999 + PreviousName string `dns:"domain-name"`
1000 + NextName string `dns:"domain-name"`
1001 +}
1002 +
1003 +func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
1004 +func (rr *TALINK) copy() RR { return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} }
1005 +func (rr *TALINK) len() int { return rr.Hdr.len() + len(rr.PreviousName) + len(rr.NextName) + 2 }
1006 +
1007 +func (rr *TALINK) String() string {
1008 + return rr.Hdr.String() +
1009 + sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
1010 +}
1011 +
1012 +type SSHFP struct {
1013 + Hdr RR_Header
1014 + Algorithm uint8
1015 + Type uint8
1016 + FingerPrint string `dns:"hex"`
1017 +}
1018 +
1019 +func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
1020 +func (rr *SSHFP) len() int { return rr.Hdr.len() + 2 + len(rr.FingerPrint)/2 }
1021 +func (rr *SSHFP) copy() RR {
1022 + return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
1023 +}
1024 +
1025 +func (rr *SSHFP) String() string {
1026 + return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
1027 + " " + strconv.Itoa(int(rr.Type)) +
1028 + " " + strings.ToUpper(rr.FingerPrint)
1029 +}
1030 +
1031 +type IPSECKEY struct {
1032 + Hdr RR_Header
1033 + Precedence uint8
1034 + // GatewayType: 1: A record, 2: AAAA record, 3: domainname.
1035 + // 0 is use for no type and GatewayName should be "." then.
1036 + GatewayType uint8
1037 + Algorithm uint8
1038 + // Gateway can be an A record, AAAA record or a domain name.
1039 + GatewayA net.IP `dns:"a"`
1040 + GatewayAAAA net.IP `dns:"aaaa"`
1041 + GatewayName string `dns:"domain-name"`
1042 + PublicKey string `dns:"base64"`
1043 +}
1044 +
1045 +func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
1046 +func (rr *IPSECKEY) copy() RR {
1047 + return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.GatewayA, rr.GatewayAAAA, rr.GatewayName, rr.PublicKey}
1048 +}
1049 +
1050 +func (rr *IPSECKEY) String() string {
1051 + s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
1052 + " " + strconv.Itoa(int(rr.GatewayType)) +
1053 + " " + strconv.Itoa(int(rr.Algorithm))
1054 + switch rr.GatewayType {
1055 + case 0:
1056 + fallthrough
1057 + case 3:
1058 + s += " " + rr.GatewayName
1059 + case 1:
1060 + s += " " + rr.GatewayA.String()
1061 + case 2:
1062 + s += " " + rr.GatewayAAAA.String()
1063 + default:
1064 + s += " ."
1065 + }
1066 + s += " " + rr.PublicKey
1067 + return s
1068 +}
1069 +
1070 +func (rr *IPSECKEY) len() int {
1071 + l := rr.Hdr.len() + 3 + 1
1072 + switch rr.GatewayType {
1073 + default:
1074 + fallthrough
1075 + case 0:
1076 + fallthrough
1077 + case 3:
1078 + l += len(rr.GatewayName)
1079 + case 1:
1080 + l += 4
1081 + case 2:
1082 + l += 16
1083 + }
1084 + return l + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
1085 +}
1086 +
1087 +type KEY struct {
1088 + DNSKEY
1089 +}
1090 +
1091 +type CDNSKEY struct {
1092 + DNSKEY
1093 +}
1094 +
1095 +type DNSKEY struct {
1096 + Hdr RR_Header
1097 + Flags uint16
1098 + Protocol uint8
1099 + Algorithm uint8
1100 + PublicKey string `dns:"base64"`
1101 +}
1102 +
1103 +func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
1104 +func (rr *DNSKEY) len() int {
1105 + return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
1106 +}
1107 +func (rr *DNSKEY) copy() RR {
1108 + return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
1109 +}
1110 +
1111 +func (rr *DNSKEY) String() string {
1112 + return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
1113 + " " + strconv.Itoa(int(rr.Protocol)) +
1114 + " " + strconv.Itoa(int(rr.Algorithm)) +
1115 + " " + rr.PublicKey
1116 +}
1117 +
1118 +type RKEY struct {
1119 + Hdr RR_Header
1120 + Flags uint16
1121 + Protocol uint8
1122 + Algorithm uint8
1123 + PublicKey string `dns:"base64"`
1124 +}
1125 +
1126 +func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
1127 +func (rr *RKEY) len() int { return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) }
1128 +func (rr *RKEY) copy() RR {
1129 + return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
1130 +}
1131 +
1132 +func (rr *RKEY) String() string {
1133 + return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
1134 + " " + strconv.Itoa(int(rr.Protocol)) +
1135 + " " + strconv.Itoa(int(rr.Algorithm)) +
1136 + " " + rr.PublicKey
1137 +}
1138 +
1139 +type NSAP struct {
1140 + Hdr RR_Header
1141 + Length uint8
1142 + Nsap string
1143 +}
1144 +
1145 +func (rr *NSAP) Header() *RR_Header { return &rr.Hdr }
1146 +func (rr *NSAP) copy() RR { return &NSAP{*rr.Hdr.copyHeader(), rr.Length, rr.Nsap} }
1147 +func (rr *NSAP) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Length)) + " " + rr.Nsap }
1148 +func (rr *NSAP) len() int { return rr.Hdr.len() + 1 + len(rr.Nsap) + 1 }
1149 +
1150 +type NSAPPTR struct {
1151 + Hdr RR_Header
1152 + Ptr string `dns:"domain-name"`
1153 +}
1154 +
1155 +func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
1156 +func (rr *NSAPPTR) copy() RR { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} }
1157 +func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
1158 +func (rr *NSAPPTR) len() int { return rr.Hdr.len() + len(rr.Ptr) }
1159 +
1160 +type NSEC3 struct {
1161 + Hdr RR_Header
1162 + Hash uint8
1163 + Flags uint8
1164 + Iterations uint16
1165 + SaltLength uint8
1166 + Salt string `dns:"size-hex"`
1167 + HashLength uint8
1168 + NextDomain string `dns:"size-base32"`
1169 + TypeBitMap []uint16 `dns:"nsec"`
1170 +}
1171 +
1172 +func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
1173 +func (rr *NSEC3) copy() RR {
1174 + cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap))
1175 + copy(cp, rr.TypeBitMap)
1176 + return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, cp}
1177 +}
1178 +
1179 +func (rr *NSEC3) String() string {
1180 + s := rr.Hdr.String()
1181 + s += strconv.Itoa(int(rr.Hash)) +
1182 + " " + strconv.Itoa(int(rr.Flags)) +
1183 + " " + strconv.Itoa(int(rr.Iterations)) +
1184 + " " + saltToString(rr.Salt) +
1185 + " " + rr.NextDomain
1186 + for i := 0; i < len(rr.TypeBitMap); i++ {
1187 + s += " " + Type(rr.TypeBitMap[i]).String()
1188 + }
1189 + return s
1190 +}
1191 +
1192 +func (rr *NSEC3) len() int {
1193 + l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
1194 + lastwindow := uint32(2 ^ 32 + 1)
1195 + for _, t := range rr.TypeBitMap {
1196 + window := t / 256
1197 + if uint32(window) != lastwindow {
1198 + l += 1 + 32
1199 + }
1200 + lastwindow = uint32(window)
1201 + }
1202 + return l
1203 +}
1204 +
1205 +type NSEC3PARAM struct {
1206 + Hdr RR_Header
1207 + Hash uint8
1208 + Flags uint8
1209 + Iterations uint16
1210 + SaltLength uint8
1211 + Salt string `dns:"hex"`
1212 +}
1213 +
1214 +func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
1215 +func (rr *NSEC3PARAM) len() int { return rr.Hdr.len() + 2 + 4 + 1 + len(rr.Salt)/2 }
1216 +func (rr *NSEC3PARAM) copy() RR {
1217 + return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
1218 +}
1219 +
1220 +func (rr *NSEC3PARAM) String() string {
1221 + s := rr.Hdr.String()
1222 + s += strconv.Itoa(int(rr.Hash)) +
1223 + " " + strconv.Itoa(int(rr.Flags)) +
1224 + " " + strconv.Itoa(int(rr.Iterations)) +
1225 + " " + saltToString(rr.Salt)
1226 + return s
1227 +}
1228 +
1229 +type TKEY struct {
1230 + Hdr RR_Header
1231 + Algorithm string `dns:"domain-name"`
1232 + Inception uint32
1233 + Expiration uint32
1234 + Mode uint16
1235 + Error uint16
1236 + KeySize uint16
1237 + Key string
1238 + OtherLen uint16
1239 + OtherData string
1240 +}
1241 +
1242 +func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
1243 +func (rr *TKEY) copy() RR {
1244 + return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
1245 +}
1246 +
1247 +func (rr *TKEY) String() string {
1248 + // It has no presentation format
1249 + return ""
1250 +}
1251 +
1252 +func (rr *TKEY) len() int {
1253 + return rr.Hdr.len() + len(rr.Algorithm) + 1 + 4 + 4 + 6 +
1254 + len(rr.Key) + 2 + len(rr.OtherData)
1255 +}
1256 +
1257 +// RFC3597 represents an unknown/generic RR.
1258 +type RFC3597 struct {
1259 + Hdr RR_Header
1260 + Rdata string `dns:"hex"`
1261 +}
1262 +
1263 +func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
1264 +func (rr *RFC3597) copy() RR { return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} }
1265 +func (rr *RFC3597) len() int { return rr.Hdr.len() + len(rr.Rdata)/2 + 2 }
1266 +
1267 +func (rr *RFC3597) String() string {
1268 + // Let's call it a hack
1269 + s := rfc3597Header(rr.Hdr)
1270 +
1271 + s += "\\# " + strconv.Itoa(len(rr.Rdata)/2) + " " + rr.Rdata
1272 + return s
1273 +}
1274 +
1275 +func rfc3597Header(h RR_Header) string {
1276 + var s string
1277 +
1278 + s += sprintName(h.Name) + "\t"
1279 + s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
1280 + s += "CLASS" + strconv.Itoa(int(h.Class)) + "\t"
1281 + s += "TYPE" + strconv.Itoa(int(h.Rrtype)) + "\t"
1282 + return s
1283 +}
1284 +
1285 +type URI struct {
1286 + Hdr RR_Header
1287 + Priority uint16
1288 + Weight uint16
1289 + Target []string `dns:"txt"`
1290 +}
1291 +
1292 +func (rr *URI) Header() *RR_Header { return &rr.Hdr }
1293 +func (rr *URI) copy() RR {
1294 + cp := make([]string, len(rr.Target), cap(rr.Target))
1295 + copy(cp, rr.Target)
1296 + return &URI{*rr.Hdr.copyHeader(), rr.Weight, rr.Priority, cp}
1297 +}
1298 +
1299 +func (rr *URI) String() string {
1300 + return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
1301 + " " + strconv.Itoa(int(rr.Weight)) + sprintTxt(rr.Target)
1302 +}
1303 +
1304 +func (rr *URI) len() int {
1305 + l := rr.Hdr.len() + 4
1306 + for _, t := range rr.Target {
1307 + l += len(t) + 1
1308 + }
1309 + return l
1310 +}
1311 +
1312 +type DHCID struct {
1313 + Hdr RR_Header
1314 + Digest string `dns:"base64"`
1315 +}
1316 +
1317 +func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
1318 +func (rr *DHCID) copy() RR { return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} }
1319 +func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
1320 +func (rr *DHCID) len() int { return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.Digest)) }
1321 +
1322 +type TLSA struct {
1323 + Hdr RR_Header
1324 + Usage uint8
1325 + Selector uint8
1326 + MatchingType uint8
1327 + Certificate string `dns:"hex"`
1328 +}
1329 +
1330 +func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
1331 +func (rr *TLSA) len() int { return rr.Hdr.len() + 3 + len(rr.Certificate)/2 }
1332 +
1333 +func (rr *TLSA) copy() RR {
1334 + return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
1335 +}
1336 +
1337 +func (rr *TLSA) String() string {
1338 + return rr.Hdr.String() +
1339 + strconv.Itoa(int(rr.Usage)) +
1340 + " " + strconv.Itoa(int(rr.Selector)) +
1341 + " " + strconv.Itoa(int(rr.MatchingType)) +
1342 + " " + rr.Certificate
1343 +}
1344 +
1345 +type HIP struct {
1346 + Hdr RR_Header
1347 + HitLength uint8
1348 + PublicKeyAlgorithm uint8
1349 + PublicKeyLength uint16
1350 + Hit string `dns:"hex"`
1351 + PublicKey string `dns:"base64"`
1352 + RendezvousServers []string `dns:"domain-name"`
1353 +}
1354 +
1355 +func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
1356 +func (rr *HIP) copy() RR {
1357 + cp := make([]string, len(rr.RendezvousServers), cap(rr.RendezvousServers))
1358 + copy(cp, rr.RendezvousServers)
1359 + return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, cp}
1360 +}
1361 +
1362 +func (rr *HIP) String() string {
1363 + s := rr.Hdr.String() +
1364 + strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
1365 + " " + rr.Hit +
1366 + " " + rr.PublicKey
1367 + for _, d := range rr.RendezvousServers {
1368 + s += " " + sprintName(d)
1369 + }
1370 + return s
1371 +}
1372 +
1373 +func (rr *HIP) len() int {
1374 + l := rr.Hdr.len() + 4 +
1375 + len(rr.Hit)/2 +
1376 + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
1377 + for _, d := range rr.RendezvousServers {
1378 + l += len(d) + 1
1379 + }
1380 + return l
1381 +}
1382 +
1383 +type NINFO struct {
1384 + Hdr RR_Header
1385 + ZSData []string `dns:"txt"`
1386 +}
1387 +
1388 +func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
1389 +func (rr *NINFO) copy() RR {
1390 + cp := make([]string, len(rr.ZSData), cap(rr.ZSData))
1391 + copy(cp, rr.ZSData)
1392 + return &NINFO{*rr.Hdr.copyHeader(), cp}
1393 +}
1394 +
1395 +func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
1396 +
1397 +func (rr *NINFO) len() int {
1398 + l := rr.Hdr.len()
1399 + for _, t := range rr.ZSData {
1400 + l += len(t) + 1
1401 + }
1402 + return l
1403 +}
1404 +
1405 +type WKS struct {
1406 + Hdr RR_Header
1407 + Address net.IP `dns:"a"`
1408 + Protocol uint8
1409 + BitMap []uint16 `dns:"wks"`
1410 +}
1411 +
1412 +func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
1413 +func (rr *WKS) len() int { return rr.Hdr.len() + net.IPv4len + 1 }
1414 +
1415 +func (rr *WKS) copy() RR {
1416 + cp := make([]uint16, len(rr.BitMap), cap(rr.BitMap))
1417 + copy(cp, rr.BitMap)
1418 + return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, cp}
1419 +}
1420 +
1421 +func (rr *WKS) String() (s string) {
1422 + s = rr.Hdr.String()
1423 + if rr.Address != nil {
1424 + s += rr.Address.String()
1425 + }
1426 + // TODO(miek): missing protocol here, see /etc/protocols
1427 + for i := 0; i < len(rr.BitMap); i++ {
1428 + // should lookup the port
1429 + s += " " + strconv.Itoa(int(rr.BitMap[i]))
1430 + }
1431 + return s
1432 +}
1433 +
1434 +type NID struct {
1435 + Hdr RR_Header
1436 + Preference uint16
1437 + NodeID uint64
1438 +}
1439 +
1440 +func (rr *NID) Header() *RR_Header { return &rr.Hdr }
1441 +func (rr *NID) copy() RR { return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} }
1442 +func (rr *NID) len() int { return rr.Hdr.len() + 2 + 8 }
1443 +
1444 +func (rr *NID) String() string {
1445 + s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1446 + node := fmt.Sprintf("%0.16x", rr.NodeID)
1447 + s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
1448 + return s
1449 +}
1450 +
1451 +type L32 struct {
1452 + Hdr RR_Header
1453 + Preference uint16
1454 + Locator32 net.IP `dns:"a"`
1455 +}
1456 +
1457 +func (rr *L32) Header() *RR_Header { return &rr.Hdr }
1458 +func (rr *L32) copy() RR { return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} }
1459 +func (rr *L32) len() int { return rr.Hdr.len() + net.IPv4len }
1460 +
1461 +func (rr *L32) String() string {
1462 + if rr.Locator32 == nil {
1463 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1464 + }
1465 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
1466 + " " + rr.Locator32.String()
1467 +}
1468 +
1469 +type L64 struct {
1470 + Hdr RR_Header
1471 + Preference uint16
1472 + Locator64 uint64
1473 +}
1474 +
1475 +func (rr *L64) Header() *RR_Header { return &rr.Hdr }
1476 +func (rr *L64) copy() RR { return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} }
1477 +func (rr *L64) len() int { return rr.Hdr.len() + 2 + 8 }
1478 +
1479 +func (rr *L64) String() string {
1480 + s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1481 + node := fmt.Sprintf("%0.16X", rr.Locator64)
1482 + s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
1483 + return s
1484 +}
1485 +
1486 +type LP struct {
1487 + Hdr RR_Header
1488 + Preference uint16
1489 + Fqdn string `dns:"domain-name"`
1490 +}
1491 +
1492 +func (rr *LP) Header() *RR_Header { return &rr.Hdr }
1493 +func (rr *LP) copy() RR { return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} }
1494 +func (rr *LP) len() int { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 }
1495 +
1496 +func (rr *LP) String() string {
1497 + return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
1498 +}
1499 +
1500 +type EUI48 struct {
1501 + Hdr RR_Header
1502 + Address uint64 `dns:"uint48"`
1503 +}
1504 +
1505 +func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
1506 +func (rr *EUI48) copy() RR { return &EUI48{*rr.Hdr.copyHeader(), rr.Address} }
1507 +func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
1508 +func (rr *EUI48) len() int { return rr.Hdr.len() + 6 }
1509 +
1510 +type EUI64 struct {
1511 + Hdr RR_Header
1512 + Address uint64
1513 +}
1514 +
1515 +func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
1516 +func (rr *EUI64) copy() RR { return &EUI64{*rr.Hdr.copyHeader(), rr.Address} }
1517 +func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
1518 +func (rr *EUI64) len() int { return rr.Hdr.len() + 8 }
1519 +
1520 +// Support in incomplete - just handle it as unknown record
1521 +/*
1522 +type CAA struct {
1523 + Hdr RR_Header
1524 + Flag uint8
1525 + Tag string
1526 + Value string `dns:"octet"`
1527 +}
1528 +
1529 +func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
1530 +func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} }
1531 +func (rr *CAA) len() int { return rr.Hdr.len() + 1 + len(rr.Tag) + 1 + len(rr.Value) }
1532 +
1533 +func (rr *CAA) String() string {
1534 + s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Flag), 10) + " " + rr.Tag
1535 + s += strconv.QuoteToASCII(rr.Value)
1536 + return s
1537 +}
1538 +*/
1539 +
1540 +type UID struct {
1541 + Hdr RR_Header
1542 + Uid uint32
1543 +}
1544 +
1545 +func (rr *UID) Header() *RR_Header { return &rr.Hdr }
1546 +func (rr *UID) copy() RR { return &UID{*rr.Hdr.copyHeader(), rr.Uid} }
1547 +func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
1548 +func (rr *UID) len() int { return rr.Hdr.len() + 4 }
1549 +
1550 +type GID struct {
1551 + Hdr RR_Header
1552 + Gid uint32
1553 +}
1554 +
1555 +func (rr *GID) Header() *RR_Header { return &rr.Hdr }
1556 +func (rr *GID) copy() RR { return &GID{*rr.Hdr.copyHeader(), rr.Gid} }
1557 +func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
1558 +func (rr *GID) len() int { return rr.Hdr.len() + 4 }
1559 +
1560 +type UINFO struct {
1561 + Hdr RR_Header
1562 + Uinfo string
1563 +}
1564 +
1565 +func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
1566 +func (rr *UINFO) copy() RR { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} }
1567 +func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
1568 +func (rr *UINFO) len() int { return rr.Hdr.len() + len(rr.Uinfo) + 1 }
1569 +
1570 +type EID struct {
1571 + Hdr RR_Header
1572 + Endpoint string `dns:"hex"`
1573 +}
1574 +
1575 +func (rr *EID) Header() *RR_Header { return &rr.Hdr }
1576 +func (rr *EID) copy() RR { return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} }
1577 +func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
1578 +func (rr *EID) len() int { return rr.Hdr.len() + len(rr.Endpoint)/2 }
1579 +
1580 +type NIMLOC struct {
1581 + Hdr RR_Header
1582 + Locator string `dns:"hex"`
1583 +}
1584 +
1585 +func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
1586 +func (rr *NIMLOC) copy() RR { return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} }
1587 +func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
1588 +func (rr *NIMLOC) len() int { return rr.Hdr.len() + len(rr.Locator)/2 }
1589 +
1590 +type OPENPGPKEY struct {
1591 + Hdr RR_Header
1592 + PublicKey string `dns:"base64"`
1593 +}
1594 +
1595 +func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
1596 +func (rr *OPENPGPKEY) copy() RR { return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} }
1597 +func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
1598 +func (rr *OPENPGPKEY) len() int {
1599 + return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
1600 +}
1601 +
1602 +// TimeToString translates the RRSIG's incep. and expir. times to the
1603 +// string representation used when printing the record.
1604 +// It takes serial arithmetic (RFC 1982) into account.
1605 +func TimeToString(t uint32) string {
1606 + mod := ((int64(t) - time.Now().Unix()) / year68) - 1
1607 + if mod < 0 {
1608 + mod = 0
1609 + }
1610 + ti := time.Unix(int64(t)-(mod*year68), 0).UTC()
1611 + return ti.Format("20060102150405")
1612 +}
1613 +
1614 +// StringToTime translates the RRSIG's incep. and expir. times from
1615 +// string values like "20110403154150" to an 32 bit integer.
1616 +// It takes serial arithmetic (RFC 1982) into account.
1617 +func StringToTime(s string) (uint32, error) {
1618 + t, e := time.Parse("20060102150405", s)
1619 + if e != nil {
1620 + return 0, e
1621 + }
1622 + mod := (t.Unix() / year68) - 1
1623 + if mod < 0 {
1624 + mod = 0
1625 + }
1626 + return uint32(t.Unix() - (mod * year68)), nil
1627 +}
1628 +
1629 +// saltToString converts a NSECX salt to uppercase and
1630 +// returns "-" when it is empty
1631 +func saltToString(s string) string {
1632 + if len(s) == 0 {
1633 + return "-"
1634 + }
1635 + return strings.ToUpper(s)
1636 +}
1637 +
1638 +func euiToString(eui uint64, bits int) (hex string) {
1639 + switch bits {
1640 + case 64:
1641 + hex = fmt.Sprintf("%16.16x", eui)
1642 + hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
1643 + "-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16]
1644 + case 48:
1645 + hex = fmt.Sprintf("%12.12x", eui)
1646 + hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
1647 + "-" + hex[8:10] + "-" + hex[10:12]
1648 + }
1649 + return
1650 +}
1651 +
1652 +// copyIP returns a copy of ip.
1653 +func copyIP(ip net.IP) net.IP {
1654 + p := make(net.IP, len(ip))
1655 + copy(p, ip)
1656 + return p
1657 +}
1658 +
1659 +// Map of constructors for each RR type.
1660 +var typeToRR = map[uint16]func() RR{
1661 + TypeA: func() RR { return new(A) },
1662 + TypeAAAA: func() RR { return new(AAAA) },
1663 + TypeAFSDB: func() RR { return new(AFSDB) },
1664 + // TypeCAA: func() RR { return new(CAA) },
1665 + TypeCDS: func() RR { return new(CDS) },
1666 + TypeCERT: func() RR { return new(CERT) },
1667 + TypeCNAME: func() RR { return new(CNAME) },
1668 + TypeDHCID: func() RR { return new(DHCID) },
1669 + TypeDLV: func() RR { return new(DLV) },
1670 + TypeDNAME: func() RR { return new(DNAME) },
1671 + TypeKEY: func() RR { return new(KEY) },
1672 + TypeDNSKEY: func() RR { return new(DNSKEY) },
1673 + TypeDS: func() RR { return new(DS) },
1674 + TypeEUI48: func() RR { return new(EUI48) },
1675 + TypeEUI64: func() RR { return new(EUI64) },
1676 + TypeGID: func() RR { return new(GID) },
1677 + TypeGPOS: func() RR { return new(GPOS) },
1678 + TypeEID: func() RR { return new(EID) },
1679 + TypeHINFO: func() RR { return new(HINFO) },
1680 + TypeHIP: func() RR { return new(HIP) },
1681 + TypeIPSECKEY: func() RR { return new(IPSECKEY) },
1682 + TypeKX: func() RR { return new(KX) },
1683 + TypeL32: func() RR { return new(L32) },
1684 + TypeL64: func() RR { return new(L64) },
1685 + TypeLOC: func() RR { return new(LOC) },
1686 + TypeLP: func() RR { return new(LP) },
1687 + TypeMB: func() RR { return new(MB) },
1688 + TypeMD: func() RR { return new(MD) },
1689 + TypeMF: func() RR { return new(MF) },
1690 + TypeMG: func() RR { return new(MG) },
1691 + TypeMINFO: func() RR { return new(MINFO) },
1692 + TypeMR: func() RR { return new(MR) },
1693 + TypeMX: func() RR { return new(MX) },
1694 + TypeNAPTR: func() RR { return new(NAPTR) },
1695 + TypeNID: func() RR { return new(NID) },
1696 + TypeNINFO: func() RR { return new(NINFO) },
1697 + TypeNIMLOC: func() RR { return new(NIMLOC) },
1698 + TypeNS: func() RR { return new(NS) },
1699 + TypeNSAP: func() RR { return new(NSAP) },
1700 + TypeNSAPPTR: func() RR { return new(NSAPPTR) },
1701 + TypeNSEC3: func() RR { return new(NSEC3) },
1702 + TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
1703 + TypeNSEC: func() RR { return new(NSEC) },
1704 + TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
1705 + TypeOPT: func() RR { return new(OPT) },
1706 + TypePTR: func() RR { return new(PTR) },
1707 + TypeRKEY: func() RR { return new(RKEY) },
1708 + TypeRP: func() RR { return new(RP) },
1709 + TypePX: func() RR { return new(PX) },
1710 + TypeSIG: func() RR { return new(SIG) },
1711 + TypeRRSIG: func() RR { return new(RRSIG) },
1712 + TypeRT: func() RR { return new(RT) },
1713 + TypeSOA: func() RR { return new(SOA) },
1714 + TypeSPF: func() RR { return new(SPF) },
1715 + TypeSRV: func() RR { return new(SRV) },
1716 + TypeSSHFP: func() RR { return new(SSHFP) },
1717 + TypeTA: func() RR { return new(TA) },
1718 + TypeTALINK: func() RR { return new(TALINK) },
1719 + TypeTKEY: func() RR { return new(TKEY) },
1720 + TypeTLSA: func() RR { return new(TLSA) },
1721 + TypeTSIG: func() RR { return new(TSIG) },
1722 + TypeTXT: func() RR { return new(TXT) },
1723 + TypeUID: func() RR { return new(UID) },
1724 + TypeUINFO: func() RR { return new(UINFO) },
1725 + TypeURI: func() RR { return new(URI) },
1726 + TypeWKS: func() RR { return new(WKS) },
1727 + TypeX25: func() RR { return new(X25) },
1728 +}
Godeps/_workspace/src/github.com/miekg/dns/types_test.go new
+42
@@ -0,0 +1,42 @@
1 +package dns
2 +
3 +import (
4 + "testing"
5 +)
6 +
7 +func TestCmToM(t *testing.T) {
8 + s := cmToM(0, 0)
9 + if s != "0.00" {
10 + t.Error("0, 0")
11 + }
12 +
13 + s = cmToM(1, 0)
14 + if s != "0.01" {
15 + t.Error("1, 0")
16 + }
17 +
18 + s = cmToM(3, 1)
19 + if s != "0.30" {
20 + t.Error("3, 1")
21 + }
22 +
23 + s = cmToM(4, 2)
24 + if s != "4" {
25 + t.Error("4, 2")
26 + }
27 +
28 + s = cmToM(5, 3)
29 + if s != "50" {
30 + t.Error("5, 3")
31 + }
32 +
33 + s = cmToM(7, 5)
34 + if s != "7000" {
35 + t.Error("7, 5")
36 + }
37 +
38 + s = cmToM(9, 9)
39 + if s != "90000000" {
40 + t.Error("9, 9")
41 + }
42 +}
Godeps/_workspace/src/github.com/miekg/dns/udp.go new
+55
@@ -0,0 +1,55 @@
1 +// +build !windows
2 +
3 +package dns
4 +
5 +import (
6 + "net"
7 + "syscall"
8 +)
9 +
10 +type sessionUDP struct {
11 + raddr *net.UDPAddr
12 + context []byte
13 +}
14 +
15 +func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr }
16 +
17 +// setUDPSocketOptions sets the UDP socket options.
18 +// This function is implemented on a per platform basis. See udp_*.go for more details
19 +func setUDPSocketOptions(conn *net.UDPConn) error {
20 + sa, err := getUDPSocketName(conn)
21 + if err != nil {
22 + return err
23 + }
24 + switch sa.(type) {
25 + case *syscall.SockaddrInet6:
26 + v6only, err := getUDPSocketOptions6Only(conn)
27 + if err != nil {
28 + return err
29 + }
30 + setUDPSocketOptions6(conn)
31 + if !v6only {
32 + setUDPSocketOptions4(conn)
33 + }
34 + case *syscall.SockaddrInet4:
35 + setUDPSocketOptions4(conn)
36 + }
37 + return nil
38 +}
39 +
40 +// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
41 +// net.UDPAddr.
42 +func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
43 + oob := make([]byte, 40)
44 + n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
45 + if err != nil {
46 + return n, nil, err
47 + }
48 + return n, &sessionUDP{raddr, oob[:oobn]}, err
49 +}
50 +
51 +// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.
52 +func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) {
53 + n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
54 + return n, err
55 +}
Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go new
+63
@@ -0,0 +1,63 @@
1 +// +build linux
2 +
3 +package dns
4 +
5 +// See:
6 +// * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and
7 +// * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/
8 +//
9 +// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing
10 +// interface, this might not always be the correct one. This code will make sure the egress
11 +// packet's interface matched the ingress' one.
12 +
13 +import (
14 + "net"
15 + "syscall"
16 +)
17 +
18 +// setUDPSocketOptions4 prepares the v4 socket for sessions.
19 +func setUDPSocketOptions4(conn *net.UDPConn) error {
20 + file, err := conn.File()
21 + if err != nil {
22 + return err
23 + }
24 + if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
25 + return err
26 + }
27 + return nil
28 +}
29 +
30 +// setUDPSocketOptions6 prepares the v6 socket for sessions.
31 +func setUDPSocketOptions6(conn *net.UDPConn) error {
32 + file, err := conn.File()
33 + if err != nil {
34 + return err
35 + }
36 + if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
37 + return err
38 + }
39 + return nil
40 +}
41 +
42 +// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined
43 +// (dualstack).
44 +func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) {
45 + file, err := conn.File()
46 + if err != nil {
47 + return false, err
48 + }
49 + // dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
50 + v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
51 + if err != nil {
52 + return false, err
53 + }
54 + return v6only == 1, nil
55 +}
56 +
57 +func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
58 + file, err := conn.File()
59 + if err != nil {
60 + return nil, err
61 + }
62 + return syscall.Getsockname(int(file.Fd()))
63 +}
Godeps/_workspace/src/github.com/miekg/dns/udp_other.go new
+17
@@ -0,0 +1,17 @@
1 +// +build !linux
2 +
3 +package dns
4 +
5 +import (
6 + "net"
7 + "syscall"
8 +)
9 +
10 +// These do nothing. See udp_linux.go for an example of how to implement this.
11 +
12 +// We tried to adhire to some kind of naming scheme.
13 +
14 +func setUDPSocketOptions4(conn *net.UDPConn) error { return nil }
15 +func setUDPSocketOptions6(conn *net.UDPConn) error { return nil }
16 +func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil }
17 +func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
Godeps/_workspace/src/github.com/miekg/dns/udp_windows.go new
+34
@@ -0,0 +1,34 @@
1 +// +build windows
2 +
3 +package dns
4 +
5 +import "net"
6 +
7 +type sessionUDP struct {
8 + raddr *net.UDPAddr
9 +}
10 +
11 +// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
12 +// net.UDPAddr.
13 +func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
14 + n, raddr, err := conn.ReadFrom(b)
15 + if err != nil {
16 + return n, nil, err
17 + }
18 + session := &sessionUDP{raddr.(*net.UDPAddr)}
19 + return n, session, err
20 +}
21 +
22 +// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.
23 +func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) {
24 + n, err := conn.WriteTo(b, session.raddr)
25 + return n, err
26 +}
27 +
28 +func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr }
29 +
30 +// setUDPSocketOptions sets the UDP socket options.
31 +// This function is implemented on a per platform basis. See udp_*.go for more details
32 +func setUDPSocketOptions(conn *net.UDPConn) error {
33 + return nil
34 +}
Godeps/_workspace/src/github.com/miekg/dns/update.go new
+129
@@ -0,0 +1,129 @@
1 +// DYNAMIC UPDATES
2 +//
3 +// Dynamic updates reuses the DNS message format, but renames three of
4 +// the sections. Question is Zone, Answer is Prerequisite, Authority is
5 +// Update, only the Additional is not renamed. See RFC 2136 for the gory details.
6 +//
7 +// You can set a rather complex set of rules for the existence of absence of
8 +// certain resource records or names in a zone to specify if resource records
9 +// should be added or removed. The table from RFC 2136 supplemented with the Go
10 +// DNS function shows which functions exist to specify the prerequisites.
11 +//
12 +// 3.2.4 - Table Of Metavalues Used In Prerequisite Section
13 +//
14 +// CLASS TYPE RDATA Meaning Function
15 +// --------------------------------------------------------------
16 +// ANY ANY empty Name is in use dns.NameUsed
17 +// ANY rrset empty RRset exists (value indep) dns.RRsetUsed
18 +// NONE ANY empty Name is not in use dns.NameNotUsed
19 +// NONE rrset empty RRset does not exist dns.RRsetNotUsed
20 +// zone rrset rr RRset exists (value dep) dns.Used
21 +//
22 +// The prerequisite section can also be left empty.
23 +// If you have decided on the prerequisites you can tell what RRs should
24 +// be added or deleted. The next table shows the options you have and
25 +// what functions to call.
26 +//
27 +// 3.4.2.6 - Table Of Metavalues Used In Update Section
28 +//
29 +// CLASS TYPE RDATA Meaning Function
30 +// ---------------------------------------------------------------
31 +// ANY ANY empty Delete all RRsets from name dns.RemoveName
32 +// ANY rrset empty Delete an RRset dns.RemoveRRset
33 +// NONE rrset rr Delete an RR from RRset dns.Remove
34 +// zone rrset rr Add to an RRset dns.Insert
35 +//
36 +package dns
37 +
38 +// NameUsed sets the RRs in the prereq section to
39 +// "Name is in use" RRs. RFC 2136 section 2.4.4.
40 +func (u *Msg) NameUsed(rr []RR) {
41 + u.Answer = make([]RR, len(rr))
42 + for i, r := range rr {
43 + u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
44 + }
45 +}
46 +
47 +// NameNotUsed sets the RRs in the prereq section to
48 +// "Name is in not use" RRs. RFC 2136 section 2.4.5.
49 +func (u *Msg) NameNotUsed(rr []RR) {
50 + u.Answer = make([]RR, len(rr))
51 + for i, r := range rr {
52 + u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}
53 + }
54 +}
55 +
56 +// Used sets the RRs in the prereq section to
57 +// "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2.
58 +func (u *Msg) Used(rr []RR) {
59 + if len(u.Question) == 0 {
60 + panic("dns: empty question section")
61 + }
62 + u.Answer = make([]RR, len(rr))
63 + for i, r := range rr {
64 + u.Answer[i] = r
65 + u.Answer[i].Header().Class = u.Question[0].Qclass
66 + }
67 +}
68 +
69 +// RRsetUsed sets the RRs in the prereq section to
70 +// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
71 +func (u *Msg) RRsetUsed(rr []RR) {
72 + u.Answer = make([]RR, len(rr))
73 + for i, r := range rr {
74 + u.Answer[i] = r
75 + u.Answer[i].Header().Class = ClassANY
76 + u.Answer[i].Header().Ttl = 0
77 + u.Answer[i].Header().Rdlength = 0
78 + }
79 +}
80 +
81 +// RRsetNotUsed sets the RRs in the prereq section to
82 +// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
83 +func (u *Msg) RRsetNotUsed(rr []RR) {
84 + u.Answer = make([]RR, len(rr))
85 + for i, r := range rr {
86 + u.Answer[i] = r
87 + u.Answer[i].Header().Class = ClassNONE
88 + u.Answer[i].Header().Rdlength = 0
89 + u.Answer[i].Header().Ttl = 0
90 + }
91 +}
92 +
93 +// Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1.
94 +func (u *Msg) Insert(rr []RR) {
95 + if len(u.Question) == 0 {
96 + panic("dns: empty question section")
97 + }
98 + u.Ns = make([]RR, len(rr))
99 + for i, r := range rr {
100 + u.Ns[i] = r
101 + u.Ns[i].Header().Class = u.Question[0].Qclass
102 + }
103 +}
104 +
105 +// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
106 +func (u *Msg) RemoveRRset(rr []RR) {
107 + u.Ns = make([]RR, len(rr))
108 + for i, r := range rr {
109 + u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}
110 + }
111 +}
112 +
113 +// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
114 +func (u *Msg) RemoveName(rr []RR) {
115 + u.Ns = make([]RR, len(rr))
116 + for i, r := range rr {
117 + u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
118 + }
119 +}
120 +
121 +// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4
122 +func (u *Msg) Remove(rr []RR) {
123 + u.Ns = make([]RR, len(rr))
124 + for i, r := range rr {
125 + u.Ns[i] = r
126 + u.Ns[i].Header().Class = ClassNONE
127 + u.Ns[i].Header().Ttl = 0
128 + }
129 +}
Godeps/_workspace/src/github.com/miekg/dns/update_test.go new
+89
@@ -0,0 +1,89 @@
1 +package dns
2 +
3 +import (
4 + "bytes"
5 + "testing"
6 +)
7 +
8 +func TestDynamicUpdateParsing(t *testing.T) {
9 + prefix := "example.com. IN "
10 + for _, typ := range TypeToString {
11 + if typ == "CAA" || typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
12 + typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" {
13 + continue
14 + }
15 + r, e := NewRR(prefix + typ)
16 + if e != nil {
17 + t.Log("failure to parse: " + prefix + typ)
18 + t.Fail()
19 + } else {
20 + t.Logf("parsed: %s", r.String())
21 + }
22 + }
23 +}
24 +
25 +func TestDynamicUpdateUnpack(t *testing.T) {
26 + // From https://github.com/miekg/dns/issues/150#issuecomment-62296803
27 + // It should be an update message for the zone "example.",
28 + // deleting the A RRset "example." and then adding an A record at "example.".
29 + // class ANY, TYPE A
30 + buf := []byte{171, 68, 40, 0, 0, 1, 0, 0, 0, 2, 0, 0, 7, 101, 120, 97, 109, 112, 108, 101, 0, 0, 6, 0, 1, 192, 12, 0, 1, 0, 255, 0, 0, 0, 0, 0, 0, 192, 12, 0, 1, 0, 1, 0, 0, 0, 0, 0, 4, 127, 0, 0, 1}
31 + msg := new(Msg)
32 + err := msg.Unpack(buf)
33 + if err != nil {
34 + t.Log("failed to unpack: " + err.Error() + "\n" + msg.String())
35 + t.Fail()
36 + }
37 +}
38 +
39 +func TestDynamicUpdateZeroRdataUnpack(t *testing.T) {
40 + m := new(Msg)
41 + rr := &RR_Header{Name: ".", Rrtype: 0, Class: 1, Ttl: ^uint32(0), Rdlength: 0}
42 + m.Answer = []RR{rr, rr, rr, rr, rr}
43 + m.Ns = m.Answer
44 + for n, s := range TypeToString {
45 + rr.Rrtype = n
46 + bytes, err := m.Pack()
47 + if err != nil {
48 + t.Logf("failed to pack %s: %v", s, err)
49 + t.Fail()
50 + continue
51 + }
52 + if err := new(Msg).Unpack(bytes); err != nil {
53 + t.Logf("failed to unpack %s: %v", s, err)
54 + t.Fail()
55 + }
56 + }
57 +}
58 +
59 +func TestRemoveRRset(t *testing.T) {
60 + // Should add a zero data RR in Class ANY with a TTL of 0
61 + // for each set mentioned in the RRs provided to it.
62 + rr, err := NewRR(". 100 IN A 127.0.0.1")
63 + if err != nil {
64 + t.Fatalf("Error constructing RR: %v", err)
65 + }
66 + m := new(Msg)
67 + m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
68 + expectstr := m.String()
69 + expect, err := m.Pack()
70 + if err != nil {
71 + t.Fatalf("Error packing expected msg: %v", err)
72 + }
73 +
74 + m.Ns = nil
75 + m.RemoveRRset([]RR{rr})
76 + actual, err := m.Pack()
77 + if err != nil {
78 + t.Fatalf("Error packing actual msg: %v", err)
79 + }
80 + if !bytes.Equal(actual, expect) {
81 + tmp := new(Msg)
82 + if err := tmp.Unpack(actual); err != nil {
83 + t.Fatalf("Error unpacking actual msg: %v", err)
84 + }
85 + t.Logf("Expected msg:\n%s", expectstr)
86 + t.Logf("Actual msg:\n%v", tmp)
87 + t.Fail()
88 + }
89 +}
Godeps/_workspace/src/github.com/miekg/dns/xfr.go new
+232
@@ -0,0 +1,232 @@
1 +package dns
2 +
3 +import (
4 + "time"
5 +)
6 +
7 +// Envelope is used when doing a zone transfer with a remote server.
8 +type Envelope struct {
9 + RR []RR // The set of RRs in the answer section of the xfr reply message.
10 + Error error // If something went wrong, this contains the error.
11 +}
12 +
13 +// A Transfer defines parameters that are used during a zone transfer.
14 +type Transfer struct {
15 + *Conn
16 + DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
17 + ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
18 + WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
19 + TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
20 + tsigTimersOnly bool
21 +}
22 +
23 +// Think we need to away to stop the transfer
24 +
25 +// In performs an incoming transfer with the server in a.
26 +func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
27 + timeout := dnsTimeout
28 + if t.DialTimeout != 0 {
29 + timeout = t.DialTimeout
30 + }
31 + t.Conn, err = DialTimeout("tcp", a, timeout)
32 + if err != nil {
33 + return nil, err
34 + }
35 + if err := t.WriteMsg(q); err != nil {
36 + return nil, err
37 + }
38 + env = make(chan *Envelope)
39 + go func() {
40 + if q.Question[0].Qtype == TypeAXFR {
41 + go t.inAxfr(q.Id, env)
42 + return
43 + }
44 + if q.Question[0].Qtype == TypeIXFR {
45 + go t.inIxfr(q.Id, env)
46 + return
47 + }
48 + }()
49 + return env, nil
50 +}
51 +
52 +func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
53 + first := true
54 + defer t.Close()
55 + defer close(c)
56 + timeout := dnsTimeout
57 + if t.ReadTimeout != 0 {
58 + timeout = t.ReadTimeout
59 + }
60 + for {
61 + t.Conn.SetReadDeadline(time.Now().Add(timeout))
62 + in, err := t.ReadMsg()
63 + if err != nil {
64 + c <- &Envelope{nil, err}
65 + return
66 + }
67 + if id != in.Id {
68 + c <- &Envelope{in.Answer, ErrId}
69 + return
70 + }
71 + if first {
72 + if !isSOAFirst(in) {
73 + c <- &Envelope{in.Answer, ErrSoa}
74 + return
75 + }
76 + first = !first
77 + // only one answer that is SOA, receive more
78 + if len(in.Answer) == 1 {
79 + t.tsigTimersOnly = true
80 + c <- &Envelope{in.Answer, nil}
81 + continue
82 + }
83 + }
84 +
85 + if !first {
86 + t.tsigTimersOnly = true // Subsequent envelopes use this.
87 + if isSOALast(in) {
88 + c <- &Envelope{in.Answer, nil}
89 + return
90 + }
91 + c <- &Envelope{in.Answer, nil}
92 + }
93 + }
94 + panic("dns: not reached")
95 +}
96 +
97 +func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
98 + serial := uint32(0) // The first serial seen is the current server serial
99 + first := true
100 + defer t.Close()
101 + defer close(c)
102 + timeout := dnsTimeout
103 + if t.ReadTimeout != 0 {
104 + timeout = t.ReadTimeout
105 + }
106 + for {
107 + t.SetReadDeadline(time.Now().Add(timeout))
108 + in, err := t.ReadMsg()
109 + if err != nil {
110 + c <- &Envelope{in.Answer, err}
111 + return
112 + }
113 + if id != in.Id {
114 + c <- &Envelope{in.Answer, ErrId}
115 + return
116 + }
117 + if first {
118 + // A single SOA RR signals "no changes"
119 + if len(in.Answer) == 1 && isSOAFirst(in) {
120 + c <- &Envelope{in.Answer, nil}
121 + return
122 + }
123 +
124 + // Check if the returned answer is ok
125 + if !isSOAFirst(in) {
126 + c <- &Envelope{in.Answer, ErrSoa}
127 + return
128 + }
129 + // This serial is important
130 + serial = in.Answer[0].(*SOA).Serial
131 + first = !first
132 + }
133 +
134 + // Now we need to check each message for SOA records, to see what we need to do
135 + if !first {
136 + t.tsigTimersOnly = true
137 + // If the last record in the IXFR contains the servers' SOA, we should quit
138 + if v, ok := in.Answer[len(in.Answer)-1].(*SOA); ok {
139 + if v.Serial == serial {
140 + c <- &Envelope{in.Answer, nil}
141 + return
142 + }
143 + }
144 + c <- &Envelope{in.Answer, nil}
145 + }
146 + }
147 +}
148 +
149 +// Out performs an outgoing transfer with the client connecting in w.
150 +// Basic use pattern:
151 +//
152 +// ch := make(chan *dns.Envelope)
153 +// tr := new(dns.Transfer)
154 +// tr.Out(w, r, ch)
155 +// c <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
156 +// close(ch)
157 +// w.Hijack()
158 +// // w.Close() // Client closes connection
159 +//
160 +// The server is responsible for sending the correct sequence of RRs through the
161 +// channel ch.
162 +func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
163 + for x := range ch {
164 + r := new(Msg)
165 + // Compress?
166 + r.SetReply(q)
167 + r.Authoritative = true
168 + // assume it fits TODO(miek): fix
169 + r.Answer = append(r.Answer, x.RR...)
170 + if err := w.WriteMsg(r); err != nil {
171 + return err
172 + }
173 + }
174 + w.TsigTimersOnly(true)
175 + return nil
176 +}
177 +
178 +// ReadMsg reads a message from the transfer connection t.
179 +func (t *Transfer) ReadMsg() (*Msg, error) {
180 + m := new(Msg)
181 + p := make([]byte, MaxMsgSize)
182 + n, err := t.Read(p)
183 + if err != nil && n == 0 {
184 + return nil, err
185 + }
186 + p = p[:n]
187 + if err := m.Unpack(p); err != nil {
188 + return nil, err
189 + }
190 + if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
191 + if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
192 + return m, ErrSecret
193 + }
194 + // Need to work on the original message p, as that was used to calculate the tsig.
195 + err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
196 + }
197 + return m, err
198 +}
199 +
200 +// WriteMsg writes a message through the transfer connection t.
201 +func (t *Transfer) WriteMsg(m *Msg) (err error) {
202 + var out []byte
203 + if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
204 + if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
205 + return ErrSecret
206 + }
207 + out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
208 + } else {
209 + out, err = m.Pack()
210 + }
211 + if err != nil {
212 + return err
213 + }
214 + if _, err = t.Write(out); err != nil {
215 + return err
216 + }
217 + return nil
218 +}
219 +
220 +func isSOAFirst(in *Msg) bool {
221 + if len(in.Answer) > 0 {
222 + return in.Answer[0].Header().Rrtype == TypeSOA
223 + }
224 + return false
225 +}
226 +
227 +func isSOALast(in *Msg) bool {
228 + if len(in.Answer) > 0 {
229 + return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
230 + }
231 + return false
232 +}
Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go new
+99
@@ -0,0 +1,99 @@
1 +package dns
2 +
3 +import (
4 + "net"
5 + "testing"
6 + "time"
7 +)
8 +
9 +func getIP(s string) string {
10 + a, e := net.LookupAddr(s)
11 + if e != nil {
12 + return ""
13 + }
14 + return a[0]
15 +}
16 +
17 +// flaky, need to setup local server and test from
18 +// that.
19 +func testClientAXFR(t *testing.T) {
20 + if testing.Short() {
21 + return
22 + }
23 + m := new(Msg)
24 + m.SetAxfr("miek.nl.")
25 +
26 + server := getIP("linode.atoom.net")
27 +
28 + tr := new(Transfer)
29 +
30 + if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
31 + t.Log("failed to setup axfr: " + err.Error())
32 + t.Fatal()
33 + } else {
34 + for ex := range a {
35 + if ex.Error != nil {
36 + t.Logf("error %s\n", ex.Error.Error())
37 + t.Fail()
38 + break
39 + }
40 + for _, rr := range ex.RR {
41 + t.Logf("%s\n", rr.String())
42 + }
43 + }
44 + }
45 +}
46 +
47 +// fails.
48 +func testClientAXFRMultipleEnvelopes(t *testing.T) {
49 + if testing.Short() {
50 + return
51 + }
52 + m := new(Msg)
53 + m.SetAxfr("nlnetlabs.nl.")
54 +
55 + server := getIP("open.nlnetlabs.nl.")
56 +
57 + tr := new(Transfer)
58 + if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
59 + t.Log("Failed to setup axfr" + err.Error() + "for server: " + server)
60 + t.Fail()
61 + return
62 + } else {
63 + for ex := range a {
64 + if ex.Error != nil {
65 + t.Logf("Error %s\n", ex.Error.Error())
66 + t.Fail()
67 + break
68 + }
69 + }
70 + }
71 +}
72 +
73 +func testClientTsigAXFR(t *testing.T) {
74 + if testing.Short() {
75 + return
76 + }
77 + m := new(Msg)
78 + m.SetAxfr("example.nl.")
79 + m.SetTsig("axfr.", HmacMD5, 300, time.Now().Unix())
80 +
81 + tr := new(Transfer)
82 + tr.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
83 +
84 + if a, err := tr.In(m, "176.58.119.54:53"); err != nil {
85 + t.Log("failed to setup axfr: " + err.Error())
86 + t.Fatal()
87 + } else {
88 + for ex := range a {
89 + if ex.Error != nil {
90 + t.Logf("error %s\n", ex.Error.Error())
91 + t.Fail()
92 + break
93 + }
94 + for _, rr := range ex.RR {
95 + t.Logf("%s\n", rr.String())
96 + }
97 + }
98 + }
99 +}
Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go new
+157
@@ -0,0 +1,157 @@
1 +package dns
2 +
3 +import (
4 + "fmt"
5 + "strconv"
6 + "strings"
7 +)
8 +
9 +// Parse the $GENERATE statement as used in BIND9 zones.
10 +// See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
11 +// We are called after '$GENERATE '. After which we expect:
12 +// * the range (12-24/2)
13 +// * lhs (ownername)
14 +// * [[ttl][class]]
15 +// * type
16 +// * rhs (rdata)
17 +// But we are lazy here, only the range is parsed *all* occurences
18 +// of $ after that are interpreted.
19 +// Any error are returned as a string value, the empty string signals
20 +// "no error".
21 +func generate(l lex, c chan lex, t chan *Token, o string) string {
22 + step := 1
23 + if i := strings.IndexAny(l.token, "/"); i != -1 {
24 + if i+1 == len(l.token) {
25 + return "bad step in $GENERATE range"
26 + }
27 + if s, e := strconv.Atoi(l.token[i+1:]); e != nil {
28 + return "bad step in $GENERATE range"
29 + } else {
30 + if s < 0 {
31 + return "bad step in $GENERATE range"
32 + }
33 + step = s
34 + }
35 + l.token = l.token[:i]
36 + }
37 + sx := strings.SplitN(l.token, "-", 2)
38 + if len(sx) != 2 {
39 + return "bad start-stop in $GENERATE range"
40 + }
41 + start, err := strconv.Atoi(sx[0])
42 + if err != nil {
43 + return "bad start in $GENERATE range"
44 + }
45 + end, err := strconv.Atoi(sx[1])
46 + if err != nil {
47 + return "bad stop in $GENERATE range"
48 + }
49 + if end < 0 || start < 0 || end <= start {
50 + return "bad range in $GENERATE range"
51 + }
52 +
53 + <-c // _BLANK
54 + // Create a complete new string, which we then parse again.
55 + s := ""
56 +BuildRR:
57 + l = <-c
58 + if l.value != _NEWLINE && l.value != _EOF {
59 + s += l.token
60 + goto BuildRR
61 + }
62 + for i := start; i <= end; i += step {
63 + var (
64 + escape bool
65 + dom string
66 + mod string
67 + err string
68 + offset int
69 + )
70 +
71 + for j := 0; j < len(s); j++ { // No 'range' because we need to jump around
72 + switch s[j] {
73 + case '\\':
74 + if escape {
75 + dom += "\\"
76 + escape = false
77 + continue
78 + }
79 + escape = true
80 + case '$':
81 + mod = "%d"
82 + offset = 0
83 + if escape {
84 + dom += "$"
85 + escape = false
86 + continue
87 + }
88 + escape = false
89 + if j+1 >= len(s) { // End of the string
90 + dom += fmt.Sprintf(mod, i+offset)
91 + continue
92 + } else {
93 + if s[j+1] == '$' {
94 + dom += "$"
95 + j++
96 + continue
97 + }
98 + }
99 + // Search for { and }
100 + if s[j+1] == '{' { // Modifier block
101 + sep := strings.Index(s[j+2:], "}")
102 + if sep == -1 {
103 + return "bad modifier in $GENERATE"
104 + }
105 + mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
106 + if err != "" {
107 + return err
108 + }
109 + j += 2 + sep // Jump to it
110 + }
111 + dom += fmt.Sprintf(mod, i+offset)
112 + default:
113 + if escape { // Pretty useless here
114 + escape = false
115 + continue
116 + }
117 + dom += string(s[j])
118 + }
119 + }
120 + // Re-parse the RR and send it on the current channel t
121 + rx, e := NewRR("$ORIGIN " + o + "\n" + dom)
122 + if e != nil {
123 + return e.(*ParseError).err
124 + }
125 + t <- &Token{RR: rx}
126 + // Its more efficient to first built the rrlist and then parse it in
127 + // one go! But is this a problem?
128 + }
129 + return ""
130 +}
131 +
132 +// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
133 +func modToPrintf(s string) (string, int, string) {
134 + xs := strings.SplitN(s, ",", 3)
135 + if len(xs) != 3 {
136 + return "", 0, "bad modifier in $GENERATE"
137 + }
138 + // xs[0] is offset, xs[1] is width, xs[2] is base
139 + if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" {
140 + return "", 0, "bad base in $GENERATE"
141 + }
142 + offset, err := strconv.Atoi(xs[0])
143 + if err != nil {
144 + return "", 0, "bad offset in $GENERATE"
145 + }
146 + width, err := strconv.Atoi(xs[1])
147 + if err != nil {
148 + return "", offset, "bad width in $GENERATE"
149 + }
150 + switch {
151 + case width < 0:
152 + return "", offset, "bad width in $GENERATE"
153 + case width == 0:
154 + return "%" + xs[1] + xs[2], offset, ""
155 + }
156 + return "%0" + xs[1] + xs[2], offset, ""
157 +}
Godeps/_workspace/src/github.com/miekg/dns/zscan.go new
+961
@@ -0,0 +1,961 @@
1 +package dns
2 +
3 +import (
4 + "io"
5 + "log"
6 + "os"
7 + "strconv"
8 + "strings"
9 +)
10 +
11 +type debugging bool
12 +
13 +const debug debugging = false
14 +
15 +func (d debugging) Printf(format string, args ...interface{}) {
16 + if d {
17 + log.Printf(format, args...)
18 + }
19 +}
20 +
21 +const maxTok = 2048 // Largest token we can return.
22 +const maxUint16 = 1<<16 - 1
23 +
24 +// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
25 +// * Add ownernames if they are left blank;
26 +// * Suppress sequences of spaces;
27 +// * Make each RR fit on one line (_NEWLINE is send as last)
28 +// * Handle comments: ;
29 +// * Handle braces - anywhere.
30 +const (
31 + // Zonefile
32 + _EOF = iota
33 + _STRING
34 + _BLANK
35 + _QUOTE
36 + _NEWLINE
37 + _RRTYPE
38 + _OWNER
39 + _CLASS
40 + _DIRORIGIN // $ORIGIN
41 + _DIRTTL // $TTL
42 + _DIRINCLUDE // $INCLUDE
43 + _DIRGENERATE // $GENERATE
44 +
45 + // Privatekey file
46 + _VALUE
47 + _KEY
48 +
49 + _EXPECT_OWNER_DIR // Ownername
50 + _EXPECT_OWNER_BL // Whitespace after the ownername
51 + _EXPECT_ANY // Expect rrtype, ttl or class
52 + _EXPECT_ANY_NOCLASS // Expect rrtype or ttl
53 + _EXPECT_ANY_NOCLASS_BL // The whitespace after _EXPECT_ANY_NOCLASS
54 + _EXPECT_ANY_NOTTL // Expect rrtype or class
55 + _EXPECT_ANY_NOTTL_BL // Whitespace after _EXPECT_ANY_NOTTL
56 + _EXPECT_RRTYPE // Expect rrtype
57 + _EXPECT_RRTYPE_BL // Whitespace BEFORE rrtype
58 + _EXPECT_RDATA // The first element of the rdata
59 + _EXPECT_DIRTTL_BL // Space after directive $TTL
60 + _EXPECT_DIRTTL // Directive $TTL
61 + _EXPECT_DIRORIGIN_BL // Space after directive $ORIGIN
62 + _EXPECT_DIRORIGIN // Directive $ORIGIN
63 + _EXPECT_DIRINCLUDE_BL // Space after directive $INCLUDE
64 + _EXPECT_DIRINCLUDE // Directive $INCLUDE
65 + _EXPECT_DIRGENERATE // Directive $GENERATE
66 + _EXPECT_DIRGENERATE_BL // Space after directive $GENERATE
67 +)
68 +
69 +// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
70 +// where the error occured.
71 +type ParseError struct {
72 + file string
73 + err string
74 + lex lex
75 +}
76 +
77 +func (e *ParseError) Error() (s string) {
78 + if e.file != "" {
79 + s = e.file + ": "
80 + }
81 + s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
82 + strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
83 + return
84 +}
85 +
86 +type lex struct {
87 + token string // text of the token
88 + tokenUpper string // uppercase text of the token
89 + length int // lenght of the token
90 + err bool // when true, token text has lexer error
91 + value uint8 // value: _STRING, _BLANK, etc.
92 + line int // line in the file
93 + column int // column in the file
94 + torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
95 + comment string // any comment text seen
96 +}
97 +
98 +// *Tokens are returned when a zone file is parsed.
99 +type Token struct {
100 + RR // the scanned resource record when error is not nil
101 + Error *ParseError // when an error occured, this has the error specifics
102 + Comment string // a potential comment positioned after the RR and on the same line
103 +}
104 +
105 +// NewRR reads the RR contained in the string s. Only the first RR is
106 +// returned. If s contains no RR, return nil with no error. The class
107 +// defaults to IN and TTL defaults to 3600. The full zone file syntax
108 +// like $TTL, $ORIGIN, etc. is supported. All fields of the returned
109 +// RR are set, except RR.Header().Rdlength which is set to 0.
110 +func NewRR(s string) (RR, error) {
111 + if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
112 + return ReadRR(strings.NewReader(s+"\n"), "")
113 + }
114 + return ReadRR(strings.NewReader(s), "")
115 +}
116 +
117 +// ReadRR reads the RR contained in q.
118 +// See NewRR for more documentation.
119 +func ReadRR(q io.Reader, filename string) (RR, error) {
120 + r := <-parseZoneHelper(q, ".", filename, 1)
121 + if r == nil {
122 + return nil, nil
123 + }
124 +
125 + if r.Error != nil {
126 + return nil, r.Error
127 + }
128 + return r.RR, nil
129 +}
130 +
131 +// ParseZone reads a RFC 1035 style one from r. It returns *Tokens on the
132 +// returned channel, which consist out the parsed RR, a potential comment or an error.
133 +// If there is an error the RR is nil. The string file is only used
134 +// in error reporting. The string origin is used as the initial origin, as
135 +// if the file would start with: $ORIGIN origin .
136 +// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
137 +// The channel t is closed by ParseZone when the end of r is reached.
138 +//
139 +// Basic usage pattern when reading from a string (z) containing the
140 +// zone data:
141 +//
142 +// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
143 +// if x.Error != nil {
144 +// // Do something with x.RR
145 +// }
146 +// }
147 +//
148 +// Comments specified after an RR (and on the same line!) are returned too:
149 +//
150 +// foo. IN A 10.0.0.1 ; this is a comment
151 +//
152 +// The text "; this is comment" is returned in Token.Comment . Comments inside the
153 +// RR are discarded. Comments on a line by themselves are discarded too.
154 +func ParseZone(r io.Reader, origin, file string) chan *Token {
155 + return parseZoneHelper(r, origin, file, 10000)
156 +}
157 +
158 +func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
159 + t := make(chan *Token, chansize)
160 + go parseZone(r, origin, file, t, 0)
161 + return t
162 +}
163 +
164 +func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
165 + defer func() {
166 + if include == 0 {
167 + close(t)
168 + }
169 + }()
170 + s := scanInit(r)
171 + c := make(chan lex, 1000)
172 + // Start the lexer
173 + go zlexer(s, c)
174 + // 6 possible beginnings of a line, _ is a space
175 + // 0. _RRTYPE -> all omitted until the rrtype
176 + // 1. _OWNER _ _RRTYPE -> class/ttl omitted
177 + // 2. _OWNER _ _STRING _ _RRTYPE -> class omitted
178 + // 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class
179 + // 4. _OWNER _ _CLASS _ _RRTYPE -> ttl omitted
180 + // 5. _OWNER _ _CLASS _ _STRING _ _RRTYPE -> class/ttl (reversed)
181 + // After detecting these, we know the _RRTYPE so we can jump to functions
182 + // handling the rdata for each of these types.
183 +
184 + if origin == "" {
185 + origin = "."
186 + }
187 + origin = Fqdn(origin)
188 + if _, ok := IsDomainName(origin); !ok {
189 + t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
190 + return
191 + }
192 +
193 + st := _EXPECT_OWNER_DIR // initial state
194 + var h RR_Header
195 + var defttl uint32 = defaultTtl
196 + var prevName string
197 + for l := range c {
198 + // Lexer spotted an error already
199 + if l.err == true {
200 + t <- &Token{Error: &ParseError{f, l.token, l}}
201 + return
202 +
203 + }
204 + switch st {
205 + case _EXPECT_OWNER_DIR:
206 + // We can also expect a directive, like $TTL or $ORIGIN
207 + h.Ttl = defttl
208 + h.Class = ClassINET
209 + switch l.value {
210 + case _NEWLINE: // Empty line
211 + st = _EXPECT_OWNER_DIR
212 + case _OWNER:
213 + h.Name = l.token
214 + if l.token[0] == '@' {
215 + h.Name = origin
216 + prevName = h.Name
217 + st = _EXPECT_OWNER_BL
218 + break
219 + }
220 + if h.Name[l.length-1] != '.' {
221 + h.Name = appendOrigin(h.Name, origin)
222 + }
223 + _, ok := IsDomainName(l.token)
224 + if !ok {
225 + t <- &Token{Error: &ParseError{f, "bad owner name", l}}
226 + return
227 + }
228 + prevName = h.Name
229 + st = _EXPECT_OWNER_BL
230 + case _DIRTTL:
231 + st = _EXPECT_DIRTTL_BL
232 + case _DIRORIGIN:
233 + st = _EXPECT_DIRORIGIN_BL
234 + case _DIRINCLUDE:
235 + st = _EXPECT_DIRINCLUDE_BL
236 + case _DIRGENERATE:
237 + st = _EXPECT_DIRGENERATE_BL
238 + case _RRTYPE: // Everthing has been omitted, this is the first thing on the line
239 + h.Name = prevName
240 + h.Rrtype = l.torc
241 + st = _EXPECT_RDATA
242 + case _CLASS: // First thing on the line is the class
243 + h.Name = prevName
244 + h.Class = l.torc
245 + st = _EXPECT_ANY_NOCLASS_BL
246 + case _BLANK:
247 + // Discard, can happen when there is nothing on the
248 + // line except the RR type
249 + case _STRING: // First thing on the is the ttl
250 + if ttl, ok := stringToTtl(l.token); !ok {
251 + t <- &Token{Error: &ParseError{f, "not a TTL", l}}
252 + return
253 + } else {
254 + h.Ttl = ttl
255 + // Don't about the defttl, we should take the $TTL value
256 + // defttl = ttl
257 + }
258 + st = _EXPECT_ANY_NOTTL_BL
259 +
260 + default:
261 + t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
262 + return
263 + }
264 + case _EXPECT_DIRINCLUDE_BL:
265 + if l.value != _BLANK {
266 + t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
267 + return
268 + }
269 + st = _EXPECT_DIRINCLUDE
270 + case _EXPECT_DIRINCLUDE:
271 + if l.value != _STRING {
272 + t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
273 + return
274 + }
275 + neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
276 + l := <-c
277 + switch l.value {
278 + case _BLANK:
279 + l := <-c
280 + if l.value == _STRING {
281 + if _, ok := IsDomainName(l.token); !ok {
282 + t <- &Token{Error: &ParseError{f, "bad origin name", l}}
283 + return
284 + }
285 + // a new origin is specified.
286 + if l.token[l.length-1] != '.' {
287 + if origin != "." { // Prevent .. endings
288 + neworigin = l.token + "." + origin
289 + } else {
290 + neworigin = l.token + origin
291 + }
292 + } else {
293 + neworigin = l.token
294 + }
295 + }
296 + case _NEWLINE, _EOF:
297 + // Ok
298 + default:
299 + t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
300 + return
301 + }
302 + // Start with the new file
303 + r1, e1 := os.Open(l.token)
304 + if e1 != nil {
305 + t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
306 + return
307 + }
308 + if include+1 > 7 {
309 + t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
310 + return
311 + }
312 + parseZone(r1, l.token, neworigin, t, include+1)
313 + st = _EXPECT_OWNER_DIR
314 + case _EXPECT_DIRTTL_BL:
315 + if l.value != _BLANK {
316 + t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
317 + return
318 + }
319 + st = _EXPECT_DIRTTL
320 + case _EXPECT_DIRTTL:
321 + if l.value != _STRING {
322 + t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
323 + return
324 + }
325 + if e, _ := slurpRemainder(c, f); e != nil {
326 + t <- &Token{Error: e}
327 + return
328 + }
329 + if ttl, ok := stringToTtl(l.token); !ok {
330 + t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
331 + return
332 + } else {
333 + defttl = ttl
334 + }
335 + st = _EXPECT_OWNER_DIR
336 + case _EXPECT_DIRORIGIN_BL:
337 + if l.value != _BLANK {
338 + t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
339 + return
340 + }
341 + st = _EXPECT_DIRORIGIN
342 + case _EXPECT_DIRORIGIN:
343 + if l.value != _STRING {
344 + t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
345 + return
346 + }
347 + if e, _ := slurpRemainder(c, f); e != nil {
348 + t <- &Token{Error: e}
349 + }
350 + if _, ok := IsDomainName(l.token); !ok {
351 + t <- &Token{Error: &ParseError{f, "bad origin name", l}}
352 + return
353 + }
354 + if l.token[l.length-1] != '.' {
355 + if origin != "." { // Prevent .. endings
356 + origin = l.token + "." + origin
357 + } else {
358 + origin = l.token + origin
359 + }
360 + } else {
361 + origin = l.token
362 + }
363 + st = _EXPECT_OWNER_DIR
364 + case _EXPECT_DIRGENERATE_BL:
365 + if l.value != _BLANK {
366 + t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
367 + return
368 + }
369 + st = _EXPECT_DIRGENERATE
370 + case _EXPECT_DIRGENERATE:
371 + if l.value != _STRING {
372 + t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
373 + return
374 + }
375 + if e := generate(l, c, t, origin); e != "" {
376 + t <- &Token{Error: &ParseError{f, e, l}}
377 + return
378 + }
379 + st = _EXPECT_OWNER_DIR
380 + case _EXPECT_OWNER_BL:
381 + if l.value != _BLANK {
382 + t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
383 + return
384 + }
385 + st = _EXPECT_ANY
386 + case _EXPECT_ANY:
387 + switch l.value {
388 + case _RRTYPE:
389 + h.Rrtype = l.torc
390 + st = _EXPECT_RDATA
391 + case _CLASS:
392 + h.Class = l.torc
393 + st = _EXPECT_ANY_NOCLASS_BL
394 + case _STRING: // TTL is this case
395 + if ttl, ok := stringToTtl(l.token); !ok {
396 + t <- &Token{Error: &ParseError{f, "not a TTL", l}}
397 + return
398 + } else {
399 + h.Ttl = ttl
400 + // defttl = ttl // don't set the defttl here
401 + }
402 + st = _EXPECT_ANY_NOTTL_BL
403 + default:
404 + t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
405 + return
406 + }
407 + case _EXPECT_ANY_NOCLASS_BL:
408 + if l.value != _BLANK {
409 + t <- &Token{Error: &ParseError{f, "no blank before class", l}}
410 + return
411 + }
412 + st = _EXPECT_ANY_NOCLASS
413 + case _EXPECT_ANY_NOTTL_BL:
414 + if l.value != _BLANK {
415 + t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
416 + return
417 + }
418 + st = _EXPECT_ANY_NOTTL
419 + case _EXPECT_ANY_NOTTL:
420 + switch l.value {
421 + case _CLASS:
422 + h.Class = l.torc
423 + st = _EXPECT_RRTYPE_BL
424 + case _RRTYPE:
425 + h.Rrtype = l.torc
426 + st = _EXPECT_RDATA
427 + default:
428 + t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
429 + return
430 + }
431 + case _EXPECT_ANY_NOCLASS:
432 + switch l.value {
433 + case _STRING: // TTL
434 + if ttl, ok := stringToTtl(l.token); !ok {
435 + t <- &Token{Error: &ParseError{f, "not a TTL", l}}
436 + return
437 + } else {
438 + h.Ttl = ttl
439 + // defttl = ttl // don't set the def ttl anymore
440 + }
441 + st = _EXPECT_RRTYPE_BL
442 + case _RRTYPE:
443 + h.Rrtype = l.torc
444 + st = _EXPECT_RDATA
445 + default:
446 + t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
447 + return
448 + }
449 + case _EXPECT_RRTYPE_BL:
450 + if l.value != _BLANK {
451 + t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
452 + return
453 + }
454 + st = _EXPECT_RRTYPE
455 + case _EXPECT_RRTYPE:
456 + if l.value != _RRTYPE {
457 + t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
458 + return
459 + }
460 + h.Rrtype = l.torc
461 + st = _EXPECT_RDATA
462 + case _EXPECT_RDATA:
463 + r, e, c1 := setRR(h, c, origin, f)
464 + if e != nil {
465 + // If e.lex is nil than we have encounter a unknown RR type
466 + // in that case we substitute our current lex token
467 + if e.lex.token == "" && e.lex.value == 0 {
468 + e.lex = l // Uh, dirty
469 + }
470 + t <- &Token{Error: e}
471 + return
472 + }
473 + t <- &Token{RR: r, Comment: c1}
474 + st = _EXPECT_OWNER_DIR
475 + }
476 + }
477 + // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
478 + // is not an error, because an empty zone file is still a zone file.
479 +}
480 +
481 +// zlexer scans the sourcefile and returns tokens on the channel c.
482 +func zlexer(s *scan, c chan lex) {
483 + var l lex
484 + str := make([]byte, maxTok) // Should be enough for any token
485 + stri := 0 // Offset in str (0 means empty)
486 + com := make([]byte, maxTok) // Hold comment text
487 + comi := 0
488 + quote := false
489 + escape := false
490 + space := false
491 + commt := false
492 + rrtype := false
493 + owner := true
494 + brace := 0
495 + x, err := s.tokenText()
496 + defer close(c)
497 + for err == nil {
498 + l.column = s.position.Column
499 + l.line = s.position.Line
500 + if stri > maxTok {
501 + l.token = "token length insufficient for parsing"
502 + l.err = true
503 + debug.Printf("[%+v]", l.token)
504 + c <- l
505 + return
506 + }
507 + if comi > maxTok {
508 + l.token = "comment length insufficient for parsing"
509 + l.err = true
510 + debug.Printf("[%+v]", l.token)
511 + c <- l
512 + return
513 + }
514 +
515 + switch x {
516 + case ' ', '\t':
517 + if escape {
518 + escape = false
519 + str[stri] = x
520 + stri++
521 + break
522 + }
523 + if quote {
524 + // Inside quotes this is legal
525 + str[stri] = x
526 + stri++
527 + break
528 + }
529 + if commt {
530 + com[comi] = x
531 + comi++
532 + break
533 + }
534 + if stri == 0 {
535 + // Space directly in the beginning, handled in the grammar
536 + } else if owner {
537 + // If we have a string and its the first, make it an owner
538 + l.value = _OWNER
539 + l.token = string(str[:stri])
540 + l.tokenUpper = strings.ToUpper(l.token)
541 + l.length = stri
542 + // escape $... start with a \ not a $, so this will work
543 + switch l.tokenUpper {
544 + case "$TTL":
545 + l.value = _DIRTTL
546 + case "$ORIGIN":
547 + l.value = _DIRORIGIN
548 + case "$INCLUDE":
549 + l.value = _DIRINCLUDE
550 + case "$GENERATE":
551 + l.value = _DIRGENERATE
552 + }
553 + debug.Printf("[7 %+v]", l.token)
554 + c <- l
555 + } else {
556 + l.value = _STRING
557 + l.token = string(str[:stri])
558 + l.tokenUpper = strings.ToUpper(l.token)
559 + l.length = stri
560 + if !rrtype {
561 + if t, ok := StringToType[l.tokenUpper]; ok {
562 + l.value = _RRTYPE
563 + l.torc = t
564 + rrtype = true
565 + } else {
566 + if strings.HasPrefix(l.tokenUpper, "TYPE") {
567 + if t, ok := typeToInt(l.token); !ok {
568 + l.token = "unknown RR type"
569 + l.err = true
570 + c <- l
571 + return
572 + } else {
573 + l.value = _RRTYPE
574 + l.torc = t
575 + }
576 + }
577 + }
578 + if t, ok := StringToClass[l.tokenUpper]; ok {
579 + l.value = _CLASS
580 + l.torc = t
581 + } else {
582 + if strings.HasPrefix(l.tokenUpper, "CLASS") {
583 + if t, ok := classToInt(l.token); !ok {
584 + l.token = "unknown class"
585 + l.err = true
586 + c <- l
587 + return
588 + } else {
589 + l.value = _CLASS
590 + l.torc = t
591 + }
592 + }
593 + }
594 + }
595 + debug.Printf("[6 %+v]", l.token)
596 + c <- l
597 + }
598 + stri = 0
599 + // I reverse space stuff here
600 + if !space && !commt {
601 + l.value = _BLANK
602 + l.token = " "
603 + l.length = 1
604 + debug.Printf("[5 %+v]", l.token)
605 + c <- l
606 + }
607 + owner = false
608 + space = true
609 + case ';':
610 + if escape {
611 + escape = false
612 + str[stri] = x
613 + stri++
614 + break
615 + }
616 + if quote {
617 + // Inside quotes this is legal
618 + str[stri] = x
619 + stri++
620 + break
621 + }
622 + if stri > 0 {
623 + l.value = _STRING
624 + l.token = string(str[:stri])
625 + l.length = stri
626 + debug.Printf("[4 %+v]", l.token)
627 + c <- l
628 + stri = 0
629 + }
630 + commt = true
631 + com[comi] = ';'
632 + comi++
633 + case '\r':
634 + escape = false
635 + if quote {
636 + str[stri] = x
637 + stri++
638 + break
639 + }
640 + // discard if outside of quotes
641 + case '\n':
642 + escape = false
643 + // Escaped newline
644 + if quote {
645 + str[stri] = x
646 + stri++
647 + break
648 + }
649 + // inside quotes this is legal
650 + if commt {
651 + // Reset a comment
652 + commt = false
653 + rrtype = false
654 + stri = 0
655 + // If not in a brace this ends the comment AND the RR
656 + if brace == 0 {
657 + owner = true
658 + owner = true
659 + l.value = _NEWLINE
660 + l.token = "\n"
661 + l.length = 1
662 + l.comment = string(com[:comi])
663 + debug.Printf("[3 %+v %+v]", l.token, l.comment)
664 + c <- l
665 + l.comment = ""
666 + comi = 0
667 + break
668 + }
669 + com[comi] = ' ' // convert newline to space
670 + comi++
671 + break
672 + }
673 +
674 + if brace == 0 {
675 + // If there is previous text, we should output it here
676 + if stri != 0 {
677 + l.value = _STRING
678 + l.token = string(str[:stri])
679 + l.tokenUpper = strings.ToUpper(l.token)
680 +
681 + l.length = stri
682 + if !rrtype {
683 + if t, ok := StringToType[l.tokenUpper]; ok {
684 + l.value = _RRTYPE
685 + l.torc = t
686 + rrtype = true
687 + }
688 + }
689 + debug.Printf("[2 %+v]", l.token)
690 + c <- l
691 + }
692 + l.value = _NEWLINE
693 + l.token = "\n"
694 + l.length = 1
695 + debug.Printf("[1 %+v]", l.token)
696 + c <- l
697 + stri = 0
698 + commt = false
699 + rrtype = false
700 + owner = true
701 + comi = 0
702 + }
703 + case '\\':
704 + // comments do not get escaped chars, everything is copied
705 + if commt {
706 + com[comi] = x
707 + comi++
708 + break
709 + }
710 + // something already escaped must be in string
711 + if escape {
712 + str[stri] = x
713 + stri++
714 + escape = false
715 + break
716 + }
717 + // something escaped outside of string gets added to string
718 + str[stri] = x
719 + stri++
720 + escape = true
721 + case '"':
722 + if commt {
723 + com[comi] = x
724 + comi++
725 + break
726 + }
727 + if escape {
728 + str[stri] = x
729 + stri++
730 + escape = false
731 + break
732 + }
733 + space = false
734 + // send previous gathered text and the quote
735 + if stri != 0 {
736 + l.value = _STRING
737 + l.token = string(str[:stri])
738 + l.length = stri
739 +
740 + debug.Printf("[%+v]", l.token)
741 + c <- l
742 + stri = 0
743 + }
744 +
745 + // send quote itself as separate token
746 + l.value = _QUOTE
747 + l.token = "\""
748 + l.length = 1
749 + c <- l
750 + quote = !quote
751 + case '(', ')':
752 + if commt {
753 + com[comi] = x
754 + comi++
755 + break
756 + }
757 + if escape {
758 + str[stri] = x
759 + stri++
760 + escape = false
761 + break
762 + }
763 + if quote {
764 + str[stri] = x
765 + stri++
766 + break
767 + }
768 + switch x {
769 + case ')':
770 + brace--
771 + if brace < 0 {
772 + l.token = "extra closing brace"
773 + l.err = true
774 + debug.Printf("[%+v]", l.token)
775 + c <- l
776 + return
777 + }
778 + case '(':
779 + brace++
780 + }
781 + default:
782 + escape = false
783 + if commt {
784 + com[comi] = x
785 + comi++
786 + break
787 + }
788 + str[stri] = x
789 + stri++
790 + space = false
791 + }
792 + x, err = s.tokenText()
793 + }
794 + if stri > 0 {
795 + // Send remainder
796 + l.token = string(str[:stri])
797 + l.length = stri
798 + l.value = _STRING
799 + debug.Printf("[%+v]", l.token)
800 + c <- l
801 + }
802 +}
803 +
804 +// Extract the class number from CLASSxx
805 +func classToInt(token string) (uint16, bool) {
806 + class, ok := strconv.Atoi(token[5:])
807 + if ok != nil || class > maxUint16 {
808 + return 0, false
809 + }
810 + return uint16(class), true
811 +}
812 +
813 +// Extract the rr number from TYPExxx
814 +func typeToInt(token string) (uint16, bool) {
815 + typ, ok := strconv.Atoi(token[4:])
816 + if ok != nil || typ > maxUint16 {
817 + return 0, false
818 + }
819 + return uint16(typ), true
820 +}
821 +
822 +// Parse things like 2w, 2m, etc, Return the time in seconds.
823 +func stringToTtl(token string) (uint32, bool) {
824 + s := uint32(0)
825 + i := uint32(0)
826 + for _, c := range token {
827 + switch c {
828 + case 's', 'S':
829 + s += i
830 + i = 0
831 + case 'm', 'M':
832 + s += i * 60
833 + i = 0
834 + case 'h', 'H':
835 + s += i * 60 * 60
836 + i = 0
837 + case 'd', 'D':
838 + s += i * 60 * 60 * 24
839 + i = 0
840 + case 'w', 'W':
841 + s += i * 60 * 60 * 24 * 7
842 + i = 0
843 + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
844 + i *= 10
845 + i += uint32(c) - '0'
846 + default:
847 + return 0, false
848 + }
849 + }
850 + return s + i, true
851 +}
852 +
853 +// Parse LOC records' <digits>[.<digits>][mM] into a
854 +// mantissa exponent format. Token should contain the entire
855 +// string (i.e. no spaces allowed)
856 +func stringToCm(token string) (e, m uint8, ok bool) {
857 + if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
858 + token = token[0 : len(token)-1]
859 + }
860 + s := strings.SplitN(token, ".", 2)
861 + var meters, cmeters, val int
862 + var err error
863 + switch len(s) {
864 + case 2:
865 + if cmeters, err = strconv.Atoi(s[1]); err != nil {
866 + return
867 + }
868 + fallthrough
869 + case 1:
870 + if meters, err = strconv.Atoi(s[0]); err != nil {
871 + return
872 + }
873 + case 0:
874 + // huh?
875 + return 0, 0, false
876 + }
877 + ok = true
878 + if meters > 0 {
879 + e = 2
880 + val = meters
881 + } else {
882 + e = 0
883 + val = cmeters
884 + }
885 + for val > 10 {
886 + e++
887 + val /= 10
888 + }
889 + if e > 9 {
890 + ok = false
891 + }
892 + m = uint8(val)
893 + return
894 +}
895 +
896 +func appendOrigin(name, origin string) string {
897 + if origin == "." {
898 + return name + origin
899 + }
900 + return name + "." + origin
901 +}
902 +
903 +// LOC record helper function
904 +func locCheckNorth(token string, latitude uint32) (uint32, bool) {
905 + switch token {
906 + case "n", "N":
907 + return LOC_EQUATOR + latitude, true
908 + case "s", "S":
909 + return LOC_EQUATOR - latitude, true
910 + }
911 + return latitude, false
912 +}
913 +
914 +// LOC record helper function
915 +func locCheckEast(token string, longitude uint32) (uint32, bool) {
916 + switch token {
917 + case "e", "E":
918 + return LOC_EQUATOR + longitude, true
919 + case "w", "W":
920 + return LOC_EQUATOR - longitude, true
921 + }
922 + return longitude, false
923 +}
924 +
925 +// "Eat" the rest of the "line". Return potential comments
926 +func slurpRemainder(c chan lex, f string) (*ParseError, string) {
927 + l := <-c
928 + com := ""
929 + switch l.value {
930 + case _BLANK:
931 + l = <-c
932 + com = l.comment
933 + if l.value != _NEWLINE && l.value != _EOF {
934 + return &ParseError{f, "garbage after rdata", l}, ""
935 + }
936 + case _NEWLINE:
937 + com = l.comment
938 + case _EOF:
939 + default:
940 + return &ParseError{f, "garbage after rdata", l}, ""
941 + }
942 + return nil, com
943 +}
944 +
945 +// Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
946 +// Used for NID and L64 record.
947 +func stringToNodeID(l lex) (uint64, *ParseError) {
948 + if len(l.token) < 19 {
949 + return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
950 + }
951 + // There must be three colons at fixes postitions, if not its a parse error
952 + if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
953 + return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
954 + }
955 + s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
956 + u, e := strconv.ParseUint(s, 16, 64)
957 + if e != nil {
958 + return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
959 + }
960 + return u, nil
961 +}
Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go new
+2184
@@ -0,0 +1,2184 @@
1 +package dns
2 +
3 +import (
4 + "encoding/base64"
5 + "net"
6 + "strconv"
7 + "strings"
8 +)
9 +
10 +type parserFunc struct {
11 + // Func defines the function that parses the tokens and returns the RR
12 + // or an error. The last string contains any comments in the line as
13 + // they returned by the lexer as well.
14 + Func func(h RR_Header, c chan lex, origin string, file string) (RR, *ParseError, string)
15 + // Signals if the RR ending is of variable length, like TXT or records
16 + // that have Hexadecimal or Base64 as their last element in the Rdata. Records
17 + // that have a fixed ending or for instance A, AAAA, SOA and etc.
18 + Variable bool
19 +}
20 +
21 +// Parse the rdata of each rrtype.
22 +// All data from the channel c is either _STRING or _BLANK.
23 +// After the rdata there may come a _BLANK and then a _NEWLINE
24 +// or immediately a _NEWLINE. If this is not the case we flag
25 +// an *ParseError: garbage after rdata.
26 +func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
27 + parserfunc, ok := typeToparserFunc[h.Rrtype]
28 + if ok {
29 + r, e, cm := parserfunc.Func(h, c, o, f)
30 + if parserfunc.Variable {
31 + return r, e, cm
32 + }
33 + if e != nil {
34 + return nil, e, ""
35 + }
36 + e, cm = slurpRemainder(c, f)
37 + if e != nil {
38 + return nil, e, ""
39 + }
40 + return r, nil, cm
41 + }
42 + // RFC3957 RR (Unknown RR handling)
43 + return setRFC3597(h, c, o, f)
44 +}
45 +
46 +// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
47 +// or an error
48 +func endingToString(c chan lex, errstr, f string) (string, *ParseError, string) {
49 + s := ""
50 + l := <-c // _STRING
51 + for l.value != _NEWLINE && l.value != _EOF {
52 + switch l.value {
53 + case _STRING:
54 + s += l.token
55 + case _BLANK: // Ok
56 + default:
57 + return "", &ParseError{f, errstr, l}, ""
58 + }
59 + l = <-c
60 + }
61 + return s, nil, l.comment
62 +}
63 +
64 +// A remainder of the rdata with embedded spaces, return the parsed string slice (sans the spaces)
65 +// or an error
66 +func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) {
67 + // Get the remaining data until we see a NEWLINE
68 + quote := false
69 + l := <-c
70 + var s []string
71 + switch l.value == _QUOTE {
72 + case true: // A number of quoted string
73 + s = make([]string, 0)
74 + empty := true
75 + for l.value != _NEWLINE && l.value != _EOF {
76 + switch l.value {
77 + case _STRING:
78 + empty = false
79 + s = append(s, l.token)
80 + case _BLANK:
81 + if quote {
82 + // _BLANK can only be seen in between txt parts.
83 + return nil, &ParseError{f, errstr, l}, ""
84 + }
85 + case _QUOTE:
86 + if empty && quote {
87 + s = append(s, "")
88 + }
89 + quote = !quote
90 + empty = true
91 + default:
92 + return nil, &ParseError{f, errstr, l}, ""
93 + }
94 + l = <-c
95 + }
96 + if quote {
97 + return nil, &ParseError{f, errstr, l}, ""
98 + }
99 + case false: // Unquoted text record
100 + s = make([]string, 1)
101 + for l.value != _NEWLINE && l.value != _EOF {
102 + s[0] += l.token
103 + l = <-c
104 + }
105 + }
106 + return s, nil, l.comment
107 +}
108 +
109 +func setA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
110 + rr := new(A)
111 + rr.Hdr = h
112 +
113 + l := <-c
114 + if l.length == 0 { // Dynamic updates.
115 + return rr, nil, ""
116 + }
117 + rr.A = net.ParseIP(l.token)
118 + if rr.A == nil {
119 + return nil, &ParseError{f, "bad A A", l}, ""
120 + }
121 + return rr, nil, ""
122 +}
123 +
124 +func setAAAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
125 + rr := new(AAAA)
126 + rr.Hdr = h
127 +
128 + l := <-c
129 + if l.length == 0 {
130 + return rr, nil, ""
131 + }
132 + rr.AAAA = net.ParseIP(l.token)
133 + if rr.AAAA == nil {
134 + return nil, &ParseError{f, "bad AAAA AAAA", l}, ""
135 + }
136 + return rr, nil, ""
137 +}
138 +
139 +func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
140 + rr := new(NS)
141 + rr.Hdr = h
142 +
143 + l := <-c
144 + rr.Ns = l.token
145 + if l.length == 0 {
146 + return rr, nil, ""
147 + }
148 + if l.token == "@" {
149 + rr.Ns = o
150 + return rr, nil, ""
151 + }
152 + _, ok := IsDomainName(l.token)
153 + if !ok {
154 + return nil, &ParseError{f, "bad NS Ns", l}, ""
155 + }
156 + if rr.Ns[l.length-1] != '.' {
157 + rr.Ns = appendOrigin(rr.Ns, o)
158 + }
159 + return rr, nil, ""
160 +}
161 +
162 +func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
163 + rr := new(PTR)
164 + rr.Hdr = h
165 +
166 + l := <-c
167 + rr.Ptr = l.token
168 + if l.length == 0 { // dynamic update rr.
169 + return rr, nil, ""
170 + }
171 + if l.token == "@" {
172 + rr.Ptr = o
173 + return rr, nil, ""
174 + }
175 + _, ok := IsDomainName(l.token)
176 + if !ok {
177 + return nil, &ParseError{f, "bad PTR Ptr", l}, ""
178 + }
179 + if rr.Ptr[l.length-1] != '.' {
180 + rr.Ptr = appendOrigin(rr.Ptr, o)
181 + }
182 + return rr, nil, ""
183 +}
184 +
185 +func setNSAPPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
186 + rr := new(NSAPPTR)
187 + rr.Hdr = h
188 +
189 + l := <-c
190 + rr.Ptr = l.token
191 + if l.length == 0 {
192 + return rr, nil, ""
193 + }
194 + if l.token == "@" {
195 + rr.Ptr = o
196 + return rr, nil, ""
197 + }
198 + _, ok := IsDomainName(l.token)
199 + if !ok {
200 + return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, ""
201 + }
202 + if rr.Ptr[l.length-1] != '.' {
203 + rr.Ptr = appendOrigin(rr.Ptr, o)
204 + }
205 + return rr, nil, ""
206 +}
207 +
208 +func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
209 + rr := new(RP)
210 + rr.Hdr = h
211 +
212 + l := <-c
213 + rr.Mbox = l.token
214 + if l.length == 0 {
215 + return rr, nil, ""
216 + }
217 + if l.token == "@" {
218 + rr.Mbox = o
219 + } else {
220 + _, ok := IsDomainName(l.token)
221 + if !ok {
222 + return nil, &ParseError{f, "bad RP Mbox", l}, ""
223 + }
224 + if rr.Mbox[l.length-1] != '.' {
225 + rr.Mbox = appendOrigin(rr.Mbox, o)
226 + }
227 + }
228 + <-c // _BLANK
229 + l = <-c
230 + rr.Txt = l.token
231 + if l.token == "@" {
232 + rr.Txt = o
233 + return rr, nil, ""
234 + }
235 + _, ok := IsDomainName(l.token)
236 + if !ok {
237 + return nil, &ParseError{f, "bad RP Txt", l}, ""
238 + }
239 + if rr.Txt[l.length-1] != '.' {
240 + rr.Txt = appendOrigin(rr.Txt, o)
241 + }
242 + return rr, nil, ""
243 +}
244 +
245 +func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
246 + rr := new(MR)
247 + rr.Hdr = h
248 +
249 + l := <-c
250 + rr.Mr = l.token
251 + if l.length == 0 {
252 + return rr, nil, ""
253 + }
254 + if l.token == "@" {
255 + rr.Mr = o
256 + return rr, nil, ""
257 + }
258 + _, ok := IsDomainName(l.token)
259 + if !ok {
260 + return nil, &ParseError{f, "bad MR Mr", l}, ""
261 + }
262 + if rr.Mr[l.length-1] != '.' {
263 + rr.Mr = appendOrigin(rr.Mr, o)
264 + }
265 + return rr, nil, ""
266 +}
267 +
268 +func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
269 + rr := new(MB)
270 + rr.Hdr = h
271 +
272 + l := <-c
273 + rr.Mb = l.token
274 + if l.length == 0 {
275 + return rr, nil, ""
276 + }
277 + if l.token == "@" {
278 + rr.Mb = o
279 + return rr, nil, ""
280 + }
281 + _, ok := IsDomainName(l.token)
282 + if !ok {
283 + return nil, &ParseError{f, "bad MB Mb", l}, ""
284 + }
285 + if rr.Mb[l.length-1] != '.' {
286 + rr.Mb = appendOrigin(rr.Mb, o)
287 + }
288 + return rr, nil, ""
289 +}
290 +
291 +func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
292 + rr := new(MG)
293 + rr.Hdr = h
294 +
295 + l := <-c
296 + rr.Mg = l.token
297 + if l.length == 0 {
298 + return rr, nil, ""
299 + }
300 + if l.token == "@" {
301 + rr.Mg = o
302 + return rr, nil, ""
303 + }
304 + _, ok := IsDomainName(l.token)
305 + if !ok {
306 + return nil, &ParseError{f, "bad MG Mg", l}, ""
307 + }
308 + if rr.Mg[l.length-1] != '.' {
309 + rr.Mg = appendOrigin(rr.Mg, o)
310 + }
311 + return rr, nil, ""
312 +}
313 +
314 +func setHINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
315 + rr := new(HINFO)
316 + rr.Hdr = h
317 +
318 + l := <-c
319 + rr.Cpu = l.token
320 + <-c // _BLANK
321 + l = <-c // _STRING
322 + rr.Os = l.token
323 +
324 + return rr, nil, ""
325 +}
326 +
327 +func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
328 + rr := new(MINFO)
329 + rr.Hdr = h
330 +
331 + l := <-c
332 + rr.Rmail = l.token
333 + if l.length == 0 {
334 + return rr, nil, ""
335 + }
336 + if l.token == "@" {
337 + rr.Rmail = o
338 + } else {
339 + _, ok := IsDomainName(l.token)
340 + if !ok {
341 + return nil, &ParseError{f, "bad MINFO Rmail", l}, ""
342 + }
343 + if rr.Rmail[l.length-1] != '.' {
344 + rr.Rmail = appendOrigin(rr.Rmail, o)
345 + }
346 + }
347 + <-c // _BLANK
348 + l = <-c
349 + rr.Email = l.token
350 + if l.token == "@" {
351 + rr.Email = o
352 + return rr, nil, ""
353 + }
354 + _, ok := IsDomainName(l.token)
355 + if !ok {
356 + return nil, &ParseError{f, "bad MINFO Email", l}, ""
357 + }
358 + if rr.Email[l.length-1] != '.' {
359 + rr.Email = appendOrigin(rr.Email, o)
360 + }
361 + return rr, nil, ""
362 +}
363 +
364 +func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
365 + rr := new(MF)
366 + rr.Hdr = h
367 +
368 + l := <-c
369 + rr.Mf = l.token
370 + if l.length == 0 {
371 + return rr, nil, ""
372 + }
373 + if l.token == "@" {
374 + rr.Mf = o
375 + return rr, nil, ""
376 + }
377 + _, ok := IsDomainName(l.token)
378 + if !ok {
379 + return nil, &ParseError{f, "bad MF Mf", l}, ""
380 + }
381 + if rr.Mf[l.length-1] != '.' {
382 + rr.Mf = appendOrigin(rr.Mf, o)
383 + }
384 + return rr, nil, ""
385 +}
386 +
387 +func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
388 + rr := new(MD)
389 + rr.Hdr = h
390 +
391 + l := <-c
392 + rr.Md = l.token
393 + if l.length == 0 {
394 + return rr, nil, ""
395 + }
396 + if l.token == "@" {
397 + rr.Md = o
398 + return rr, nil, ""
399 + }
400 + _, ok := IsDomainName(l.token)
401 + if !ok {
402 + return nil, &ParseError{f, "bad MD Md", l}, ""
403 + }
404 + if rr.Md[l.length-1] != '.' {
405 + rr.Md = appendOrigin(rr.Md, o)
406 + }
407 + return rr, nil, ""
408 +}
409 +
410 +func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
411 + rr := new(MX)
412 + rr.Hdr = h
413 +
414 + l := <-c
415 + if l.length == 0 {
416 + return rr, nil, ""
417 + }
418 + if i, e := strconv.Atoi(l.token); e != nil {
419 + return nil, &ParseError{f, "bad MX Pref", l}, ""
420 + } else {
421 + rr.Preference = uint16(i)
422 + }
423 + <-c // _BLANK
424 + l = <-c // _STRING
425 + rr.Mx = l.token
426 + if l.token == "@" {
427 + rr.Mx = o
428 + return rr, nil, ""
429 + }
430 + _, ok := IsDomainName(l.token)
431 + if !ok || l.length == 0 {
432 + return nil, &ParseError{f, "bad MX Mx", l}, ""
433 + }
434 + if rr.Mx[l.length-1] != '.' {
435 + rr.Mx = appendOrigin(rr.Mx, o)
436 + }
437 + return rr, nil, ""
438 +}
439 +
440 +func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
441 + rr := new(RT)
442 + rr.Hdr = h
443 + l := <-c
444 + if l.length == 0 {
445 + return rr, nil, ""
446 + }
447 + if i, e := strconv.Atoi(l.token); e != nil {
448 + return nil, &ParseError{f, "bad RT Preference", l}, ""
449 + } else {
450 + rr.Preference = uint16(i)
451 + }
452 + <-c // _BLANK
453 + l = <-c // _STRING
454 + rr.Host = l.token
455 + if l.token == "@" {
456 + rr.Host = o
457 + return rr, nil, ""
458 + }
459 + _, ok := IsDomainName(l.token)
460 + if !ok || l.length == 0 {
461 + return nil, &ParseError{f, "bad RT Host", l}, ""
462 + }
463 + if rr.Host[l.length-1] != '.' {
464 + rr.Host = appendOrigin(rr.Host, o)
465 + }
466 + return rr, nil, ""
467 +}
468 +
469 +func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
470 + rr := new(AFSDB)
471 + rr.Hdr = h
472 +
473 + l := <-c
474 + if l.length == 0 {
475 + return rr, nil, ""
476 + }
477 + if i, e := strconv.Atoi(l.token); e != nil {
478 + return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
479 + } else {
480 + rr.Subtype = uint16(i)
481 + }
482 + <-c // _BLANK
483 + l = <-c // _STRING
484 + rr.Hostname = l.token
485 + if l.token == "@" {
486 + rr.Hostname = o
487 + return rr, nil, ""
488 + }
489 + _, ok := IsDomainName(l.token)
490 + if !ok || l.length == 0 {
491 + return nil, &ParseError{f, "bad AFSDB Hostname", l}, ""
492 + }
493 + if rr.Hostname[l.length-1] != '.' {
494 + rr.Hostname = appendOrigin(rr.Hostname, o)
495 + }
496 + return rr, nil, ""
497 +}
498 +
499 +func setX25(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
500 + rr := new(X25)
501 + rr.Hdr = h
502 +
503 + l := <-c
504 + rr.PSDNAddress = l.token
505 + return rr, nil, ""
506 +}
507 +
508 +func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
509 + rr := new(KX)
510 + rr.Hdr = h
511 +
512 + l := <-c
513 + if l.length == 0 {
514 + return rr, nil, ""
515 + }
516 + if i, e := strconv.Atoi(l.token); e != nil {
517 + return nil, &ParseError{f, "bad KX Pref", l}, ""
518 + } else {
519 + rr.Preference = uint16(i)
520 + }
521 + <-c // _BLANK
522 + l = <-c // _STRING
523 + rr.Exchanger = l.token
524 + if l.token == "@" {
525 + rr.Exchanger = o
526 + return rr, nil, ""
527 + }
528 + _, ok := IsDomainName(l.token)
529 + if !ok || l.length == 0 {
530 + return nil, &ParseError{f, "bad KX Exchanger", l}, ""
531 + }
532 + if rr.Exchanger[l.length-1] != '.' {
533 + rr.Exchanger = appendOrigin(rr.Exchanger, o)
534 + }
535 + return rr, nil, ""
536 +}
537 +
538 +func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
539 + rr := new(CNAME)
540 + rr.Hdr = h
541 +
542 + l := <-c
543 + rr.Target = l.token
544 + if l.length == 0 {
545 + return rr, nil, ""
546 + }
547 + if l.token == "@" {
548 + rr.Target = o
549 + return rr, nil, ""
550 + }
551 + _, ok := IsDomainName(l.token)
552 + if !ok || l.length == 0 {
553 + return nil, &ParseError{f, "bad CNAME Target", l}, ""
554 + }
555 + if rr.Target[l.length-1] != '.' {
556 + rr.Target = appendOrigin(rr.Target, o)
557 + }
558 + return rr, nil, ""
559 +}
560 +
561 +func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
562 + rr := new(DNAME)
563 + rr.Hdr = h
564 +
565 + l := <-c
566 + rr.Target = l.token
567 + if l.length == 0 {
568 + return rr, nil, ""
569 + }
570 + if l.token == "@" {
571 + rr.Target = o
572 + return rr, nil, ""
573 + }
574 + _, ok := IsDomainName(l.token)
575 + if !ok {
576 + return nil, &ParseError{f, "bad CNAME Target", l}, ""
577 + }
578 + if rr.Target[l.length-1] != '.' {
579 + rr.Target = appendOrigin(rr.Target, o)
580 + }
581 + return rr, nil, ""
582 +}
583 +
584 +func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
585 + rr := new(SOA)
586 + rr.Hdr = h
587 +
588 + l := <-c
589 + rr.Ns = l.token
590 + if l.length == 0 {
591 + return rr, nil, ""
592 + }
593 + <-c // _BLANK
594 + if l.token == "@" {
595 + rr.Ns = o
596 + } else {
597 + _, ok := IsDomainName(l.token)
598 + if !ok {
599 + return nil, &ParseError{f, "bad SOA Ns", l}, ""
600 + }
601 + if rr.Ns[l.length-1] != '.' {
602 + rr.Ns = appendOrigin(rr.Ns, o)
603 + }
604 + }
605 +
606 + l = <-c
607 + rr.Mbox = l.token
608 + if l.token == "@" {
609 + rr.Mbox = o
610 + } else {
611 + _, ok := IsDomainName(l.token)
612 + if !ok || l.length == 0 {
613 + return nil, &ParseError{f, "bad SOA Mbox", l}, ""
614 + }
615 + if rr.Mbox[l.length-1] != '.' {
616 + rr.Mbox = appendOrigin(rr.Mbox, o)
617 + }
618 + }
619 + <-c // _BLANK
620 +
621 + var (
622 + v uint32
623 + ok bool
624 + )
625 + for i := 0; i < 5; i++ {
626 + l = <-c
627 + if j, e := strconv.Atoi(l.token); e != nil {
628 + if i == 0 {
629 + // Serial should be a number
630 + return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
631 + }
632 + if v, ok = stringToTtl(l.token); !ok {
633 + return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
634 +
635 + }
636 + } else {
637 + v = uint32(j)
638 + }
639 + switch i {
640 + case 0:
641 + rr.Serial = v
642 + <-c // _BLANK
643 + case 1:
644 + rr.Refresh = v
645 + <-c // _BLANK
646 + case 2:
647 + rr.Retry = v
648 + <-c // _BLANK
649 + case 3:
650 + rr.Expire = v
651 + <-c // _BLANK
652 + case 4:
653 + rr.Minttl = v
654 + }
655 + }
656 + return rr, nil, ""
657 +}
658 +
659 +func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
660 + rr := new(SRV)
661 + rr.Hdr = h
662 +
663 + l := <-c
664 + if l.length == 0 {
665 + return rr, nil, ""
666 + }
667 + if i, e := strconv.Atoi(l.token); e != nil {
668 + return nil, &ParseError{f, "bad SRV Priority", l}, ""
669 + } else {
670 + rr.Priority = uint16(i)
671 + }
672 + <-c // _BLANK
673 + l = <-c // _STRING
674 + if i, e := strconv.Atoi(l.token); e != nil {
675 + return nil, &ParseError{f, "bad SRV Weight", l}, ""
676 + } else {
677 + rr.Weight = uint16(i)
678 + }
679 + <-c // _BLANK
680 + l = <-c // _STRING
681 + if i, e := strconv.Atoi(l.token); e != nil {
682 + return nil, &ParseError{f, "bad SRV Port", l}, ""
683 + } else {
684 + rr.Port = uint16(i)
685 + }
686 + <-c // _BLANK
687 + l = <-c // _STRING
688 + rr.Target = l.token
689 + if l.token == "@" {
690 + rr.Target = o
691 + return rr, nil, ""
692 + }
693 + _, ok := IsDomainName(l.token)
694 + if !ok || l.length == 0 {
695 + return nil, &ParseError{f, "bad SRV Target", l}, ""
696 + }
697 + if rr.Target[l.length-1] != '.' {
698 + rr.Target = appendOrigin(rr.Target, o)
699 + }
700 + return rr, nil, ""
701 +}
702 +
703 +func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
704 + rr := new(NAPTR)
705 + rr.Hdr = h
706 +
707 + l := <-c
708 + if l.length == 0 {
709 + return rr, nil, ""
710 + }
711 + if i, e := strconv.Atoi(l.token); e != nil {
712 + return nil, &ParseError{f, "bad NAPTR Order", l}, ""
713 + } else {
714 + rr.Order = uint16(i)
715 + }
716 + <-c // _BLANK
717 + l = <-c // _STRING
718 + if i, e := strconv.Atoi(l.token); e != nil {
719 + return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
720 + } else {
721 + rr.Preference = uint16(i)
722 + }
723 + // Flags
724 + <-c // _BLANK
725 + l = <-c // _QUOTE
726 + if l.value != _QUOTE {
727 + return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
728 + }
729 + l = <-c // Either String or Quote
730 + if l.value == _STRING {
731 + rr.Flags = l.token
732 + l = <-c // _QUOTE
733 + if l.value != _QUOTE {
734 + return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
735 + }
736 + } else if l.value == _QUOTE {
737 + rr.Flags = ""
738 + } else {
739 + return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
740 + }
741 +
742 + // Service
743 + <-c // _BLANK
744 + l = <-c // _QUOTE
745 + if l.value != _QUOTE {
746 + return nil, &ParseError{f, "bad NAPTR Service", l}, ""
747 + }
748 + l = <-c // Either String or Quote
749 + if l.value == _STRING {
750 + rr.Service = l.token
751 + l = <-c // _QUOTE
752 + if l.value != _QUOTE {
753 + return nil, &ParseError{f, "bad NAPTR Service", l}, ""
754 + }
755 + } else if l.value == _QUOTE {
756 + rr.Service = ""
757 + } else {
758 + return nil, &ParseError{f, "bad NAPTR Service", l}, ""
759 + }
760 +
761 + // Regexp
762 + <-c // _BLANK
763 + l = <-c // _QUOTE
764 + if l.value != _QUOTE {
765 + return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
766 + }
767 + l = <-c // Either String or Quote
768 + if l.value == _STRING {
769 + rr.Regexp = l.token
770 + l = <-c // _QUOTE
771 + if l.value != _QUOTE {
772 + return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
773 + }
774 + } else if l.value == _QUOTE {
775 + rr.Regexp = ""
776 + } else {
777 + return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
778 + }
779 + // After quote no space??
780 + <-c // _BLANK
781 + l = <-c // _STRING
782 + rr.Replacement = l.token
783 + if l.token == "@" {
784 + rr.Replacement = o
785 + return rr, nil, ""
786 + }
787 + _, ok := IsDomainName(l.token)
788 + if !ok || l.length == 0 {
789 + return nil, &ParseError{f, "bad NAPTR Replacement", l}, ""
790 + }
791 + if rr.Replacement[l.length-1] != '.' {
792 + rr.Replacement = appendOrigin(rr.Replacement, o)
793 + }
794 + return rr, nil, ""
795 +}
796 +
797 +func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
798 + rr := new(TALINK)
799 + rr.Hdr = h
800 +
801 + l := <-c
802 + rr.PreviousName = l.token
803 + if l.length == 0 {
804 + return rr, nil, ""
805 + }
806 + if l.token == "@" {
807 + rr.PreviousName = o
808 + } else {
809 + _, ok := IsDomainName(l.token)
810 + if !ok {
811 + return nil, &ParseError{f, "bad TALINK PreviousName", l}, ""
812 + }
813 + if rr.PreviousName[l.length-1] != '.' {
814 + rr.PreviousName = appendOrigin(rr.PreviousName, o)
815 + }
816 + }
817 + <-c // _BLANK
818 + l = <-c
819 + rr.NextName = l.token
820 + if l.token == "@" {
821 + rr.NextName = o
822 + return rr, nil, ""
823 + }
824 + _, ok := IsDomainName(l.token)
825 + if !ok || l.length == 0 {
826 + return nil, &ParseError{f, "bad TALINK NextName", l}, ""
827 + }
828 + if rr.NextName[l.length-1] != '.' {
829 + rr.NextName = appendOrigin(rr.NextName, o)
830 + }
831 + return rr, nil, ""
832 +}
833 +
834 +func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
835 + rr := new(LOC)
836 + rr.Hdr = h
837 + // Non zero defaults for LOC record, see RFC 1876, Section 3.
838 + rr.HorizPre = 165 // 10000
839 + rr.VertPre = 162 // 10
840 + rr.Size = 18 // 1
841 + ok := false
842 + // North
843 + l := <-c
844 + if l.length == 0 {
845 + return rr, nil, ""
846 + }
847 + if i, e := strconv.Atoi(l.token); e != nil {
848 + return nil, &ParseError{f, "bad LOC Latitude", l}, ""
849 + } else {
850 + rr.Latitude = 1000 * 60 * 60 * uint32(i)
851 + }
852 + <-c // _BLANK
853 + // Either number, 'N' or 'S'
854 + l = <-c
855 + if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
856 + goto East
857 + }
858 + if i, e := strconv.Atoi(l.token); e != nil {
859 + return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
860 + } else {
861 + rr.Latitude += 1000 * 60 * uint32(i)
862 + }
863 + <-c // _BLANK
864 + l = <-c
865 + if i, e := strconv.ParseFloat(l.token, 32); e != nil {
866 + return nil, &ParseError{f, "bad LOC Latitude seconds", l}, ""
867 + } else {
868 + rr.Latitude += uint32(1000 * i)
869 + }
870 + <-c // _BLANK
871 + // Either number, 'N' or 'S'
872 + l = <-c
873 + if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
874 + goto East
875 + }
876 + // If still alive, flag an error
877 + return nil, &ParseError{f, "bad LOC Latitude North/South", l}, ""
878 +
879 +East:
880 + // East
881 + <-c // _BLANK
882 + l = <-c
883 + if i, e := strconv.Atoi(l.token); e != nil {
884 + return nil, &ParseError{f, "bad LOC Longitude", l}, ""
885 + } else {
886 + rr.Longitude = 1000 * 60 * 60 * uint32(i)
887 + }
888 + <-c // _BLANK
889 + // Either number, 'E' or 'W'
890 + l = <-c
891 + if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
892 + goto Altitude
893 + }
894 + if i, e := strconv.Atoi(l.token); e != nil {
895 + return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
896 + } else {
897 + rr.Longitude += 1000 * 60 * uint32(i)
898 + }
899 + <-c // _BLANK
900 + l = <-c
901 + if i, e := strconv.ParseFloat(l.token, 32); e != nil {
902 + return nil, &ParseError{f, "bad LOC Longitude seconds", l}, ""
903 + } else {
904 + rr.Longitude += uint32(1000 * i)
905 + }
906 + <-c // _BLANK
907 + // Either number, 'E' or 'W'
908 + l = <-c
909 + if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
910 + goto Altitude
911 + }
912 + // If still alive, flag an error
913 + return nil, &ParseError{f, "bad LOC Longitude East/West", l}, ""
914 +
915 +Altitude:
916 + <-c // _BLANK
917 + l = <-c
918 + if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' {
919 + l.token = l.token[0 : len(l.token)-1]
920 + }
921 + if i, e := strconv.ParseFloat(l.token, 32); e != nil {
922 + return nil, &ParseError{f, "bad LOC Altitude", l}, ""
923 + } else {
924 + rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
925 + }
926 +
927 + // And now optionally the other values
928 + l = <-c
929 + count := 0
930 + for l.value != _NEWLINE && l.value != _EOF {
931 + switch l.value {
932 + case _STRING:
933 + switch count {
934 + case 0: // Size
935 + if e, m, ok := stringToCm(l.token); !ok {
936 + return nil, &ParseError{f, "bad LOC Size", l}, ""
937 + } else {
938 + rr.Size = (e & 0x0f) | (m << 4 & 0xf0)
939 + }
940 + case 1: // HorizPre
941 + if e, m, ok := stringToCm(l.token); !ok {
942 + return nil, &ParseError{f, "bad LOC HorizPre", l}, ""
943 + } else {
944 + rr.HorizPre = (e & 0x0f) | (m << 4 & 0xf0)
945 + }
946 + case 2: // VertPre
947 + if e, m, ok := stringToCm(l.token); !ok {
948 + return nil, &ParseError{f, "bad LOC VertPre", l}, ""
949 + } else {
950 + rr.VertPre = (e & 0x0f) | (m << 4 & 0xf0)
951 + }
952 + }
953 + count++
954 + case _BLANK:
955 + // Ok
956 + default:
957 + return nil, &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}, ""
958 + }
959 + l = <-c
960 + }
961 + return rr, nil, ""
962 +}
963 +
964 +func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
965 + rr := new(HIP)
966 + rr.Hdr = h
967 +
968 + // HitLength is not represented
969 + l := <-c
970 + if l.length == 0 {
971 + return rr, nil, l.comment
972 + }
973 + if i, e := strconv.Atoi(l.token); e != nil {
974 + return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
975 + } else {
976 + rr.PublicKeyAlgorithm = uint8(i)
977 + }
978 + <-c // _BLANK
979 + l = <-c // _STRING
980 + rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6.
981 + rr.HitLength = uint8(len(rr.Hit)) / 2
982 +
983 + <-c // _BLANK
984 + l = <-c // _STRING
985 + rr.PublicKey = l.token // This cannot contain spaces
986 + rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey)))
987 +
988 + // RendezvousServers (if any)
989 + l = <-c
990 + xs := make([]string, 0)
991 + for l.value != _NEWLINE && l.value != _EOF {
992 + switch l.value {
993 + case _STRING:
994 + if l.token == "@" {
995 + xs = append(xs, o)
996 + continue
997 + }
998 + _, ok := IsDomainName(l.token)
999 + if !ok || l.length == 0 {
1000 + return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
1001 + }
1002 + if l.token[l.length-1] != '.' {
1003 + l.token = appendOrigin(l.token, o)
1004 + }
1005 + xs = append(xs, l.token)
1006 + case _BLANK:
1007 + // Ok
1008 + default:
1009 + return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
1010 + }
1011 + l = <-c
1012 + }
1013 + rr.RendezvousServers = xs
1014 + return rr, nil, l.comment
1015 +}
1016 +
1017 +func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1018 + rr := new(CERT)
1019 + rr.Hdr = h
1020 +
1021 + l := <-c
1022 + if l.length == 0 {
1023 + return rr, nil, l.comment
1024 + }
1025 + if v, ok := StringToCertType[l.token]; ok {
1026 + rr.Type = v
1027 + } else if i, e := strconv.Atoi(l.token); e != nil {
1028 + return nil, &ParseError{f, "bad CERT Type", l}, ""
1029 + } else {
1030 + rr.Type = uint16(i)
1031 + }
1032 + <-c // _BLANK
1033 + l = <-c // _STRING
1034 + if i, e := strconv.Atoi(l.token); e != nil {
1035 + return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
1036 + } else {
1037 + rr.KeyTag = uint16(i)
1038 + }
1039 + <-c // _BLANK
1040 + l = <-c // _STRING
1041 + if v, ok := StringToAlgorithm[l.token]; ok {
1042 + rr.Algorithm = v
1043 + } else if i, e := strconv.Atoi(l.token); e != nil {
1044 + return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
1045 + } else {
1046 + rr.Algorithm = uint8(i)
1047 + }
1048 + s, e, c1 := endingToString(c, "bad CERT Certificate", f)
1049 + if e != nil {
1050 + return nil, e, c1
1051 + }
1052 + rr.Certificate = s
1053 + return rr, nil, c1
1054 +}
1055 +
1056 +func setOPENPGPKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1057 + rr := new(OPENPGPKEY)
1058 + rr.Hdr = h
1059 +
1060 + s, e, c1 := endingToString(c, "bad OPENPGPKEY PublicKey", f)
1061 + if e != nil {
1062 + return nil, e, c1
1063 + }
1064 + rr.PublicKey = s
1065 + return rr, nil, c1
1066 +}
1067 +
1068 +func setSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1069 + r, e, s := setRRSIG(h, c, o, f)
1070 + if r != nil {
1071 + return &SIG{*r.(*RRSIG)}, e, s
1072 + }
1073 + return nil, e, s
1074 +}
1075 +
1076 +func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1077 + rr := new(RRSIG)
1078 + rr.Hdr = h
1079 + l := <-c
1080 + if l.length == 0 {
1081 + return rr, nil, l.comment
1082 + }
1083 + if t, ok := StringToType[l.tokenUpper]; !ok {
1084 + if strings.HasPrefix(l.tokenUpper, "TYPE") {
1085 + if t, ok = typeToInt(l.tokenUpper); !ok {
1086 + return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
1087 + } else {
1088 + rr.TypeCovered = t
1089 + }
1090 + } else {
1091 + return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
1092 + }
1093 + } else {
1094 + rr.TypeCovered = t
1095 + }
1096 + <-c // _BLANK
1097 + l = <-c
1098 + if i, err := strconv.Atoi(l.token); err != nil {
1099 + return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
1100 + } else {
1101 + rr.Algorithm = uint8(i)
1102 + }
1103 + <-c // _BLANK
1104 + l = <-c
1105 + if i, err := strconv.Atoi(l.token); err != nil {
1106 + return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
1107 + } else {
1108 + rr.Labels = uint8(i)
1109 + }
1110 + <-c // _BLANK
1111 + l = <-c
1112 + if i, err := strconv.Atoi(l.token); err != nil {
1113 + return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
1114 + } else {
1115 + rr.OrigTtl = uint32(i)
1116 + }
1117 + <-c // _BLANK
1118 + l = <-c
1119 + if i, err := StringToTime(l.token); err != nil {
1120 + // Try to see if all numeric and use it as epoch
1121 + if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
1122 + // TODO(miek): error out on > MAX_UINT32, same below
1123 + rr.Expiration = uint32(i)
1124 + } else {
1125 + return nil, &ParseError{f, "bad RRSIG Expiration", l}, ""
1126 + }
1127 + } else {
1128 + rr.Expiration = i
1129 + }
1130 + <-c // _BLANK
1131 + l = <-c
1132 + if i, err := StringToTime(l.token); err != nil {
1133 + if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
1134 + rr.Inception = uint32(i)
1135 + } else {
1136 + return nil, &ParseError{f, "bad RRSIG Inception", l}, ""
1137 + }
1138 + } else {
1139 + rr.Inception = i
1140 + }
1141 + <-c // _BLANK
1142 + l = <-c
1143 + if i, err := strconv.Atoi(l.token); err != nil {
1144 + return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
1145 + } else {
1146 + rr.KeyTag = uint16(i)
1147 + }
1148 + <-c // _BLANK
1149 + l = <-c
1150 + rr.SignerName = l.token
1151 + if l.token == "@" {
1152 + rr.SignerName = o
1153 + } else {
1154 + _, ok := IsDomainName(l.token)
1155 + if !ok || l.length == 0 {
1156 + return nil, &ParseError{f, "bad RRSIG SignerName", l}, ""
1157 + }
1158 + if rr.SignerName[l.length-1] != '.' {
1159 + rr.SignerName = appendOrigin(rr.SignerName, o)
1160 + }
1161 + }
1162 + s, e, c1 := endingToString(c, "bad RRSIG Signature", f)
1163 + if e != nil {
1164 + return nil, e, c1
1165 + }
1166 + rr.Signature = s
1167 + return rr, nil, c1
1168 +}
1169 +
1170 +func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1171 + rr := new(NSEC)
1172 + rr.Hdr = h
1173 +
1174 + l := <-c
1175 + rr.NextDomain = l.token
1176 + if l.length == 0 {
1177 + return rr, nil, l.comment
1178 + }
1179 + if l.token == "@" {
1180 + rr.NextDomain = o
1181 + } else {
1182 + _, ok := IsDomainName(l.token)
1183 + if !ok {
1184 + return nil, &ParseError{f, "bad NSEC NextDomain", l}, ""
1185 + }
1186 + if rr.NextDomain[l.length-1] != '.' {
1187 + rr.NextDomain = appendOrigin(rr.NextDomain, o)
1188 + }
1189 + }
1190 +
1191 + rr.TypeBitMap = make([]uint16, 0)
1192 + var (
1193 + k uint16
1194 + ok bool
1195 + )
1196 + l = <-c
1197 + for l.value != _NEWLINE && l.value != _EOF {
1198 + switch l.value {
1199 + case _BLANK:
1200 + // Ok
1201 + case _STRING:
1202 + if k, ok = StringToType[l.tokenUpper]; !ok {
1203 + if k, ok = typeToInt(l.tokenUpper); !ok {
1204 + return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
1205 + }
1206 + }
1207 + rr.TypeBitMap = append(rr.TypeBitMap, k)
1208 + default:
1209 + return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
1210 + }
1211 + l = <-c
1212 + }
1213 + return rr, nil, l.comment
1214 +}
1215 +
1216 +func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1217 + rr := new(NSEC3)
1218 + rr.Hdr = h
1219 +
1220 + l := <-c
1221 + if l.length == 0 {
1222 + return rr, nil, l.comment
1223 + }
1224 + if i, e := strconv.Atoi(l.token); e != nil {
1225 + return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
1226 + } else {
1227 + rr.Hash = uint8(i)
1228 + }
1229 + <-c // _BLANK
1230 + l = <-c
1231 + if i, e := strconv.Atoi(l.token); e != nil {
1232 + return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
1233 + } else {
1234 + rr.Flags = uint8(i)
1235 + }
1236 + <-c // _BLANK
1237 + l = <-c
1238 + if i, e := strconv.Atoi(l.token); e != nil {
1239 + return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
1240 + } else {
1241 + rr.Iterations = uint16(i)
1242 + }
1243 + <-c
1244 + l = <-c
1245 + if len(l.token) == 0 {
1246 + return nil, &ParseError{f, "bad NSEC3 Salt", l}, ""
1247 + }
1248 + rr.SaltLength = uint8(len(l.token)) / 2
1249 + rr.Salt = l.token
1250 +
1251 + <-c
1252 + l = <-c
1253 + rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits)
1254 + rr.NextDomain = l.token
1255 +
1256 + rr.TypeBitMap = make([]uint16, 0)
1257 + var (
1258 + k uint16
1259 + ok bool
1260 + )
1261 + l = <-c
1262 + for l.value != _NEWLINE && l.value != _EOF {
1263 + switch l.value {
1264 + case _BLANK:
1265 + // Ok
1266 + case _STRING:
1267 + if k, ok = StringToType[l.tokenUpper]; !ok {
1268 + if k, ok = typeToInt(l.tokenUpper); !ok {
1269 + return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
1270 + }
1271 + }
1272 + rr.TypeBitMap = append(rr.TypeBitMap, k)
1273 + default:
1274 + return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
1275 + }
1276 + l = <-c
1277 + }
1278 + return rr, nil, l.comment
1279 +}
1280 +
1281 +func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1282 + rr := new(NSEC3PARAM)
1283 + rr.Hdr = h
1284 +
1285 + l := <-c
1286 + if l.length == 0 {
1287 + return rr, nil, ""
1288 + }
1289 + if i, e := strconv.Atoi(l.token); e != nil {
1290 + return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
1291 + } else {
1292 + rr.Hash = uint8(i)
1293 + }
1294 + <-c // _BLANK
1295 + l = <-c
1296 + if i, e := strconv.Atoi(l.token); e != nil {
1297 + return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
1298 + } else {
1299 + rr.Flags = uint8(i)
1300 + }
1301 + <-c // _BLANK
1302 + l = <-c
1303 + if i, e := strconv.Atoi(l.token); e != nil {
1304 + return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
1305 + } else {
1306 + rr.Iterations = uint16(i)
1307 + }
1308 + <-c
1309 + l = <-c
1310 + rr.SaltLength = uint8(len(l.token))
1311 + rr.Salt = l.token
1312 + return rr, nil, ""
1313 +}
1314 +
1315 +func setEUI48(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1316 + rr := new(EUI48)
1317 + rr.Hdr = h
1318 +
1319 + l := <-c
1320 + if l.length == 0 {
1321 + return rr, nil, ""
1322 + }
1323 + if l.length != 17 {
1324 + return nil, &ParseError{f, "bad EUI48 Address", l}, ""
1325 + }
1326 + addr := make([]byte, 12)
1327 + dash := 0
1328 + for i := 0; i < 10; i += 2 {
1329 + addr[i] = l.token[i+dash]
1330 + addr[i+1] = l.token[i+1+dash]
1331 + dash++
1332 + if l.token[i+1+dash] != '-' {
1333 + return nil, &ParseError{f, "bad EUI48 Address", l}, ""
1334 + }
1335 + }
1336 + addr[10] = l.token[15]
1337 + addr[11] = l.token[16]
1338 +
1339 + if i, e := strconv.ParseUint(string(addr), 16, 48); e != nil {
1340 + return nil, &ParseError{f, "bad EUI48 Address", l}, ""
1341 + } else {
1342 + rr.Address = i
1343 + }
1344 + return rr, nil, ""
1345 +}
1346 +
1347 +func setEUI64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1348 + rr := new(EUI64)
1349 + rr.Hdr = h
1350 +
1351 + l := <-c
1352 + if l.length == 0 {
1353 + return rr, nil, ""
1354 + }
1355 + if l.length != 23 {
1356 + return nil, &ParseError{f, "bad EUI64 Address", l}, ""
1357 + }
1358 + addr := make([]byte, 16)
1359 + dash := 0
1360 + for i := 0; i < 14; i += 2 {
1361 + addr[i] = l.token[i+dash]
1362 + addr[i+1] = l.token[i+1+dash]
1363 + dash++
1364 + if l.token[i+1+dash] != '-' {
1365 + return nil, &ParseError{f, "bad EUI64 Address", l}, ""
1366 + }
1367 + }
1368 + addr[14] = l.token[21]
1369 + addr[15] = l.token[22]
1370 +
1371 + if i, e := strconv.ParseUint(string(addr), 16, 64); e != nil {
1372 + return nil, &ParseError{f, "bad EUI68 Address", l}, ""
1373 + } else {
1374 + rr.Address = uint64(i)
1375 + }
1376 + return rr, nil, ""
1377 +}
1378 +
1379 +func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1380 + rr := new(WKS)
1381 + rr.Hdr = h
1382 +
1383 + l := <-c
1384 + if l.length == 0 {
1385 + return rr, nil, l.comment
1386 + }
1387 + rr.Address = net.ParseIP(l.token)
1388 + if rr.Address == nil {
1389 + return nil, &ParseError{f, "bad WKS Address", l}, ""
1390 + }
1391 +
1392 + <-c // _BLANK
1393 + l = <-c
1394 + proto := "tcp"
1395 + if i, e := strconv.Atoi(l.token); e != nil {
1396 + return nil, &ParseError{f, "bad WKS Protocol", l}, ""
1397 + } else {
1398 + rr.Protocol = uint8(i)
1399 + switch rr.Protocol {
1400 + case 17:
1401 + proto = "udp"
1402 + case 6:
1403 + proto = "tcp"
1404 + default:
1405 + return nil, &ParseError{f, "bad WKS Protocol", l}, ""
1406 + }
1407 + }
1408 +
1409 + <-c
1410 + l = <-c
1411 + rr.BitMap = make([]uint16, 0)
1412 + var (
1413 + k int
1414 + err error
1415 + )
1416 + for l.value != _NEWLINE && l.value != _EOF {
1417 + switch l.value {
1418 + case _BLANK:
1419 + // Ok
1420 + case _STRING:
1421 + if k, err = net.LookupPort(proto, l.token); err != nil {
1422 + if i, e := strconv.Atoi(l.token); e != nil { // If a number use that
1423 + rr.BitMap = append(rr.BitMap, uint16(i))
1424 + } else {
1425 + return nil, &ParseError{f, "bad WKS BitMap", l}, ""
1426 + }
1427 + }
1428 + rr.BitMap = append(rr.BitMap, uint16(k))
1429 + default:
1430 + return nil, &ParseError{f, "bad WKS BitMap", l}, ""
1431 + }
1432 + l = <-c
1433 + }
1434 + return rr, nil, l.comment
1435 +}
1436 +
1437 +func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1438 + rr := new(SSHFP)
1439 + rr.Hdr = h
1440 +
1441 + l := <-c
1442 + if l.length == 0 {
1443 + return rr, nil, ""
1444 + }
1445 + if i, e := strconv.Atoi(l.token); e != nil {
1446 + return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
1447 + } else {
1448 + rr.Algorithm = uint8(i)
1449 + }
1450 + <-c // _BLANK
1451 + l = <-c
1452 + if i, e := strconv.Atoi(l.token); e != nil {
1453 + return nil, &ParseError{f, "bad SSHFP Type", l}, ""
1454 + } else {
1455 + rr.Type = uint8(i)
1456 + }
1457 + <-c // _BLANK
1458 + l = <-c
1459 + rr.FingerPrint = l.token
1460 + return rr, nil, ""
1461 +}
1462 +
1463 +func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) {
1464 + rr := new(DNSKEY)
1465 + rr.Hdr = h
1466 +
1467 + l := <-c
1468 + if l.length == 0 {
1469 + return rr, nil, l.comment
1470 + }
1471 + if i, e := strconv.Atoi(l.token); e != nil {
1472 + return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
1473 + } else {
1474 + rr.Flags = uint16(i)
1475 + }
1476 + <-c // _BLANK
1477 + l = <-c // _STRING
1478 + if i, e := strconv.Atoi(l.token); e != nil {
1479 + return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
1480 + } else {
1481 + rr.Protocol = uint8(i)
1482 + }
1483 + <-c // _BLANK
1484 + l = <-c // _STRING
1485 + if i, e := strconv.Atoi(l.token); e != nil {
1486 + return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
1487 + } else {
1488 + rr.Algorithm = uint8(i)
1489 + }
1490 + s, e, c1 := endingToString(c, "bad "+typ+" PublicKey", f)
1491 + if e != nil {
1492 + return nil, e, c1
1493 + }
1494 + rr.PublicKey = s
1495 + return rr, nil, c1
1496 +}
1497 +
1498 +func setKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1499 + r, e, s := setDNSKEYs(h, c, o, f, "KEY")
1500 + if r != nil {
1501 + return &KEY{*r.(*DNSKEY)}, e, s
1502 + }
1503 + return nil, e, s
1504 +}
1505 +
1506 +func setDNSKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1507 + r, e, s := setDNSKEYs(h, c, o, f, "DNSKEY")
1508 + return r, e, s
1509 +}
1510 +
1511 +func setCDNSKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1512 + r, e, s := setDNSKEYs(h, c, o, f, "CDNSKEY")
1513 + if r != nil {
1514 + return &CDNSKEY{*r.(*DNSKEY)}, e, s
1515 + }
1516 + return nil, e, s
1517 +}
1518 +
1519 +func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1520 + rr := new(RKEY)
1521 + rr.Hdr = h
1522 +
1523 + l := <-c
1524 + if l.length == 0 {
1525 + return rr, nil, l.comment
1526 + }
1527 + if i, e := strconv.Atoi(l.token); e != nil {
1528 + return nil, &ParseError{f, "bad RKEY Flags", l}, ""
1529 + } else {
1530 + rr.Flags = uint16(i)
1531 + }
1532 + <-c // _BLANK
1533 + l = <-c // _STRING
1534 + if i, e := strconv.Atoi(l.token); e != nil {
1535 + return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
1536 + } else {
1537 + rr.Protocol = uint8(i)
1538 + }
1539 + <-c // _BLANK
1540 + l = <-c // _STRING
1541 + if i, e := strconv.Atoi(l.token); e != nil {
1542 + return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
1543 + } else {
1544 + rr.Algorithm = uint8(i)
1545 + }
1546 + s, e, c1 := endingToString(c, "bad RKEY PublicKey", f)
1547 + if e != nil {
1548 + return nil, e, c1
1549 + }
1550 + rr.PublicKey = s
1551 + return rr, nil, c1
1552 +}
1553 +
1554 +func setEID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1555 + rr := new(EID)
1556 + rr.Hdr = h
1557 + s, e, c1 := endingToString(c, "bad EID Endpoint", f)
1558 + if e != nil {
1559 + return nil, e, c1
1560 + }
1561 + rr.Endpoint = s
1562 + return rr, nil, c1
1563 +}
1564 +
1565 +func setNIMLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1566 + rr := new(NIMLOC)
1567 + rr.Hdr = h
1568 + s, e, c1 := endingToString(c, "bad NIMLOC Locator", f)
1569 + if e != nil {
1570 + return nil, e, c1
1571 + }
1572 + rr.Locator = s
1573 + return rr, nil, c1
1574 +}
1575 +
1576 +func setNSAP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1577 + rr := new(NSAP)
1578 + rr.Hdr = h
1579 + l := <-c
1580 + if l.length == 0 {
1581 + return rr, nil, l.comment
1582 + }
1583 + if i, e := strconv.Atoi(l.token); e != nil {
1584 + return nil, &ParseError{f, "bad NSAP Length", l}, ""
1585 + } else {
1586 + rr.Length = uint8(i)
1587 + }
1588 + <-c // _BLANK
1589 + s, e, c1 := endingToString(c, "bad NSAP Nsap", f)
1590 + if e != nil {
1591 + return nil, e, c1
1592 + }
1593 + rr.Nsap = s
1594 + return rr, nil, c1
1595 +}
1596 +
1597 +func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1598 + rr := new(GPOS)
1599 + rr.Hdr = h
1600 + l := <-c
1601 + if l.length == 0 {
1602 + return rr, nil, ""
1603 + }
1604 + if _, e := strconv.ParseFloat(l.token, 64); e != nil {
1605 + return nil, &ParseError{f, "bad GPOS Longitude", l}, ""
1606 + } else {
1607 + rr.Longitude = l.token
1608 + }
1609 + <-c // _BLANK
1610 + l = <-c
1611 + if _, e := strconv.ParseFloat(l.token, 64); e != nil {
1612 + return nil, &ParseError{f, "bad GPOS Latitude", l}, ""
1613 + } else {
1614 + rr.Latitude = l.token
1615 + }
1616 + <-c // _BLANK
1617 + l = <-c
1618 + if _, e := strconv.ParseFloat(l.token, 64); e != nil {
1619 + return nil, &ParseError{f, "bad GPOS Altitude", l}, ""
1620 + } else {
1621 + rr.Altitude = l.token
1622 + }
1623 + return rr, nil, ""
1624 +}
1625 +
1626 +func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) {
1627 + rr := new(DS)
1628 + rr.Hdr = h
1629 + l := <-c
1630 + if l.length == 0 {
1631 + return rr, nil, l.comment
1632 + }
1633 + if i, e := strconv.Atoi(l.token); e != nil {
1634 + return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
1635 + } else {
1636 + rr.KeyTag = uint16(i)
1637 + }
1638 + <-c // _BLANK
1639 + l = <-c
1640 + if i, e := strconv.Atoi(l.token); e != nil {
1641 + if i, ok := StringToAlgorithm[l.tokenUpper]; !ok {
1642 + return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
1643 + } else {
1644 + rr.Algorithm = i
1645 + }
1646 + } else {
1647 + rr.Algorithm = uint8(i)
1648 + }
1649 + <-c // _BLANK
1650 + l = <-c
1651 + if i, e := strconv.Atoi(l.token); e != nil {
1652 + return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
1653 + } else {
1654 + rr.DigestType = uint8(i)
1655 + }
1656 + s, e, c1 := endingToString(c, "bad "+typ+" Digest", f)
1657 + if e != nil {
1658 + return nil, e, c1
1659 + }
1660 + rr.Digest = s
1661 + return rr, nil, c1
1662 +}
1663 +
1664 +func setDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1665 + r, e, s := setDSs(h, c, o, f, "DS")
1666 + return r, e, s
1667 +}
1668 +
1669 +func setDLV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1670 + r, e, s := setDSs(h, c, o, f, "DLV")
1671 + if r != nil {
1672 + return &DLV{*r.(*DS)}, e, s
1673 + }
1674 + return nil, e, s
1675 +}
1676 +
1677 +func setCDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1678 + r, e, s := setDSs(h, c, o, f, "DLV")
1679 + if r != nil {
1680 + return &CDS{*r.(*DS)}, e, s
1681 + }
1682 + return nil, e, s
1683 +}
1684 +
1685 +func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1686 + rr := new(TA)
1687 + rr.Hdr = h
1688 + l := <-c
1689 + if l.length == 0 {
1690 + return rr, nil, l.comment
1691 + }
1692 + if i, e := strconv.Atoi(l.token); e != nil {
1693 + return nil, &ParseError{f, "bad TA KeyTag", l}, ""
1694 + } else {
1695 + rr.KeyTag = uint16(i)
1696 + }
1697 + <-c // _BLANK
1698 + l = <-c
1699 + if i, e := strconv.Atoi(l.token); e != nil {
1700 + if i, ok := StringToAlgorithm[l.tokenUpper]; !ok {
1701 + return nil, &ParseError{f, "bad TA Algorithm", l}, ""
1702 + } else {
1703 + rr.Algorithm = i
1704 + }
1705 + } else {
1706 + rr.Algorithm = uint8(i)
1707 + }
1708 + <-c // _BLANK
1709 + l = <-c
1710 + if i, e := strconv.Atoi(l.token); e != nil {
1711 + return nil, &ParseError{f, "bad TA DigestType", l}, ""
1712 + } else {
1713 + rr.DigestType = uint8(i)
1714 + }
1715 + s, e, c1 := endingToString(c, "bad TA Digest", f)
1716 + if e != nil {
1717 + return nil, e, c1
1718 + }
1719 + rr.Digest = s
1720 + return rr, nil, c1
1721 +}
1722 +
1723 +func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1724 + rr := new(TLSA)
1725 + rr.Hdr = h
1726 + l := <-c
1727 + if l.length == 0 {
1728 + return rr, nil, l.comment
1729 + }
1730 + if i, e := strconv.Atoi(l.token); e != nil {
1731 + return nil, &ParseError{f, "bad TLSA Usage", l}, ""
1732 + } else {
1733 + rr.Usage = uint8(i)
1734 + }
1735 + <-c // _BLANK
1736 + l = <-c
1737 + if i, e := strconv.Atoi(l.token); e != nil {
1738 + return nil, &ParseError{f, "bad TLSA Selector", l}, ""
1739 + } else {
1740 + rr.Selector = uint8(i)
1741 + }
1742 + <-c // _BLANK
1743 + l = <-c
1744 + if i, e := strconv.Atoi(l.token); e != nil {
1745 + return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
1746 + } else {
1747 + rr.MatchingType = uint8(i)
1748 + }
1749 + s, e, c1 := endingToString(c, "bad TLSA Certificate", f)
1750 + if e != nil {
1751 + return nil, e, c1
1752 + }
1753 + rr.Certificate = s
1754 + return rr, nil, c1
1755 +}
1756 +
1757 +func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1758 + rr := new(RFC3597)
1759 + rr.Hdr = h
1760 + l := <-c
1761 + if l.token != "\\#" {
1762 + return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
1763 + }
1764 + <-c // _BLANK
1765 + l = <-c
1766 + rdlength, e := strconv.Atoi(l.token)
1767 + if e != nil {
1768 + return nil, &ParseError{f, "bad RFC3597 Rdata ", l}, ""
1769 + }
1770 +
1771 + s, e1, c1 := endingToString(c, "bad RFC3597 Rdata", f)
1772 + if e1 != nil {
1773 + return nil, e1, c1
1774 + }
1775 + if rdlength*2 != len(s) {
1776 + return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
1777 + }
1778 + rr.Rdata = s
1779 + return rr, nil, c1
1780 +}
1781 +
1782 +func setSPF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1783 + rr := new(SPF)
1784 + rr.Hdr = h
1785 +
1786 + s, e, c1 := endingToTxtSlice(c, "bad SPF Txt", f)
1787 + if e != nil {
1788 + return nil, e, ""
1789 + }
1790 + rr.Txt = s
1791 + return rr, nil, c1
1792 +}
1793 +
1794 +func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1795 + rr := new(TXT)
1796 + rr.Hdr = h
1797 +
1798 + // No _BLANK reading here, because this is all rdata is TXT
1799 + s, e, c1 := endingToTxtSlice(c, "bad TXT Txt", f)
1800 + if e != nil {
1801 + return nil, e, ""
1802 + }
1803 + rr.Txt = s
1804 + return rr, nil, c1
1805 +}
1806 +
1807 +// identical to setTXT
1808 +func setNINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1809 + rr := new(NINFO)
1810 + rr.Hdr = h
1811 +
1812 + s, e, c1 := endingToTxtSlice(c, "bad NINFO ZSData", f)
1813 + if e != nil {
1814 + return nil, e, ""
1815 + }
1816 + rr.ZSData = s
1817 + return rr, nil, c1
1818 +}
1819 +
1820 +func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1821 + rr := new(URI)
1822 + rr.Hdr = h
1823 +
1824 + l := <-c
1825 + if l.length == 0 {
1826 + return rr, nil, l.comment
1827 + }
1828 + if i, e := strconv.Atoi(l.token); e != nil {
1829 + return nil, &ParseError{f, "bad URI Priority", l}, ""
1830 + } else {
1831 + rr.Priority = uint16(i)
1832 + }
1833 + <-c // _BLANK
1834 + l = <-c
1835 + if i, e := strconv.Atoi(l.token); e != nil {
1836 + return nil, &ParseError{f, "bad URI Weight", l}, ""
1837 + } else {
1838 + rr.Weight = uint16(i)
1839 + }
1840 +
1841 + <-c // _BLANK
1842 + s, e, c1 := endingToTxtSlice(c, "bad URI Target", f)
1843 + if e != nil {
1844 + return nil, e, ""
1845 + }
1846 + rr.Target = s
1847 + return rr, nil, c1
1848 +}
1849 +
1850 +func setDHCID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1851 + // awesome record to parse!
1852 + rr := new(DHCID)
1853 + rr.Hdr = h
1854 +
1855 + s, e, c1 := endingToString(c, "bad DHCID Digest", f)
1856 + if e != nil {
1857 + return nil, e, c1
1858 + }
1859 + rr.Digest = s
1860 + return rr, nil, c1
1861 +}
1862 +
1863 +func setNID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1864 + rr := new(NID)
1865 + rr.Hdr = h
1866 +
1867 + l := <-c
1868 + if l.length == 0 {
1869 + return rr, nil, ""
1870 + }
1871 + if i, e := strconv.Atoi(l.token); e != nil {
1872 + return nil, &ParseError{f, "bad NID Preference", l}, ""
1873 + } else {
1874 + rr.Preference = uint16(i)
1875 + }
1876 + <-c // _BLANK
1877 + l = <-c // _STRING
1878 + u, err := stringToNodeID(l)
1879 + if err != nil {
1880 + return nil, err, ""
1881 + }
1882 + rr.NodeID = u
1883 + return rr, nil, ""
1884 +}
1885 +
1886 +func setL32(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1887 + rr := new(L32)
1888 + rr.Hdr = h
1889 +
1890 + l := <-c
1891 + if l.length == 0 {
1892 + return rr, nil, ""
1893 + }
1894 + if i, e := strconv.Atoi(l.token); e != nil {
1895 + return nil, &ParseError{f, "bad L32 Preference", l}, ""
1896 + } else {
1897 + rr.Preference = uint16(i)
1898 + }
1899 + <-c // _BLANK
1900 + l = <-c // _STRING
1901 + rr.Locator32 = net.ParseIP(l.token)
1902 + if rr.Locator32 == nil {
1903 + return nil, &ParseError{f, "bad L32 Locator", l}, ""
1904 + }
1905 + return rr, nil, ""
1906 +}
1907 +
1908 +func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1909 + rr := new(LP)
1910 + rr.Hdr = h
1911 +
1912 + l := <-c
1913 + if l.length == 0 {
1914 + return rr, nil, ""
1915 + }
1916 + if i, e := strconv.Atoi(l.token); e != nil {
1917 + return nil, &ParseError{f, "bad LP Preference", l}, ""
1918 + } else {
1919 + rr.Preference = uint16(i)
1920 + }
1921 + <-c // _BLANK
1922 + l = <-c // _STRING
1923 + rr.Fqdn = l.token
1924 + if l.length == 0 {
1925 + return rr, nil, ""
1926 + }
1927 + if l.token == "@" {
1928 + rr.Fqdn = o
1929 + return rr, nil, ""
1930 + }
1931 + _, ok := IsDomainName(l.token)
1932 + if !ok || l.length == 0 {
1933 + return nil, &ParseError{f, "bad LP Fqdn", l}, ""
1934 + }
1935 + if rr.Fqdn[l.length-1] != '.' {
1936 + rr.Fqdn = appendOrigin(rr.Fqdn, o)
1937 + }
1938 + return rr, nil, ""
1939 +}
1940 +
1941 +func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1942 + rr := new(L64)
1943 + rr.Hdr = h
1944 +
1945 + l := <-c
1946 + if l.length == 0 {
1947 + return rr, nil, ""
1948 + }
1949 + if i, e := strconv.Atoi(l.token); e != nil {
1950 + return nil, &ParseError{f, "bad L64 Preference", l}, ""
1951 + } else {
1952 + rr.Preference = uint16(i)
1953 + }
1954 + <-c // _BLANK
1955 + l = <-c // _STRING
1956 + u, err := stringToNodeID(l)
1957 + if err != nil {
1958 + return nil, err, ""
1959 + }
1960 + rr.Locator64 = u
1961 + return rr, nil, ""
1962 +}
1963 +
1964 +func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1965 + rr := new(UID)
1966 + rr.Hdr = h
1967 + l := <-c
1968 + if l.length == 0 {
1969 + return rr, nil, ""
1970 + }
1971 + if i, e := strconv.Atoi(l.token); e != nil {
1972 + return nil, &ParseError{f, "bad UID Uid", l}, ""
1973 + } else {
1974 + rr.Uid = uint32(i)
1975 + }
1976 + return rr, nil, ""
1977 +}
1978 +
1979 +func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1980 + rr := new(GID)
1981 + rr.Hdr = h
1982 + l := <-c
1983 + if l.length == 0 {
1984 + return rr, nil, ""
1985 + }
1986 + if i, e := strconv.Atoi(l.token); e != nil {
1987 + return nil, &ParseError{f, "bad GID Gid", l}, ""
1988 + } else {
1989 + rr.Gid = uint32(i)
1990 + }
1991 + return rr, nil, ""
1992 +}
1993 +
1994 +func setUINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
1995 + rr := new(UINFO)
1996 + rr.Hdr = h
1997 + s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
1998 + if e != nil {
1999 + return nil, e, ""
2000 + }
2001 + rr.Uinfo = s[0] // silently discard anything above
2002 + return rr, nil, c1
2003 +}
2004 +
2005 +func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
2006 + rr := new(PX)
2007 + rr.Hdr = h
2008 +
2009 + l := <-c
2010 + if l.length == 0 {
2011 + return rr, nil, ""
2012 + }
2013 + if i, e := strconv.Atoi(l.token); e != nil {
2014 + return nil, &ParseError{f, "bad PX Preference", l}, ""
2015 + } else {
2016 + rr.Preference = uint16(i)
2017 + }
2018 + <-c // _BLANK
2019 + l = <-c // _STRING
2020 + rr.Map822 = l.token
2021 + if l.length == 0 {
2022 + return rr, nil, ""
2023 + }
2024 + if l.token == "@" {
2025 + rr.Map822 = o
2026 + return rr, nil, ""
2027 + }
2028 + _, ok := IsDomainName(l.token)
2029 + if !ok {
2030 + return nil, &ParseError{f, "bad PX Map822", l}, ""
2031 + }
2032 + if rr.Map822[l.length-1] != '.' {
2033 + rr.Map822 = appendOrigin(rr.Map822, o)
2034 + }
2035 + <-c // _BLANK
2036 + l = <-c // _STRING
2037 + rr.Mapx400 = l.token
2038 + if l.token == "@" {
2039 + rr.Mapx400 = o
2040 + return rr, nil, ""
2041 + }
2042 + _, ok = IsDomainName(l.token)
2043 + if !ok || l.length == 0 {
2044 + return nil, &ParseError{f, "bad PX Mapx400", l}, ""
2045 + }
2046 + if rr.Mapx400[l.length-1] != '.' {
2047 + rr.Mapx400 = appendOrigin(rr.Mapx400, o)
2048 + }
2049 + return rr, nil, ""
2050 +}
2051 +
2052 +func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
2053 + rr := new(IPSECKEY)
2054 + rr.Hdr = h
2055 + l := <-c
2056 + if l.length == 0 {
2057 + return rr, nil, l.comment
2058 + }
2059 + if i, err := strconv.Atoi(l.token); err != nil {
2060 + return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, ""
2061 + } else {
2062 + rr.Precedence = uint8(i)
2063 + }
2064 + <-c // _BLANK
2065 + l = <-c
2066 + if i, err := strconv.Atoi(l.token); err != nil {
2067 + return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, ""
2068 + } else {
2069 + rr.GatewayType = uint8(i)
2070 + }
2071 + <-c // _BLANK
2072 + l = <-c
2073 + if i, err := strconv.Atoi(l.token); err != nil {
2074 + return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, ""
2075 + } else {
2076 + rr.Algorithm = uint8(i)
2077 + }
2078 +
2079 + // Now according to GatewayType we can have different elements here
2080 + <-c // _BLANK
2081 + l = <-c
2082 + switch rr.GatewayType {
2083 + case 0:
2084 + fallthrough
2085 + case 3:
2086 + rr.GatewayName = l.token
2087 + if l.token == "@" {
2088 + rr.GatewayName = o
2089 + }
2090 + _, ok := IsDomainName(l.token)
2091 + if !ok {
2092 + return nil, &ParseError{f, "bad IPSECKEY GatewayName", l}, ""
2093 + }
2094 + if rr.GatewayName[l.length-1] != '.' {
2095 + rr.GatewayName = appendOrigin(rr.GatewayName, o)
2096 + }
2097 + case 1:
2098 + rr.GatewayA = net.ParseIP(l.token)
2099 + if rr.GatewayA == nil {
2100 + return nil, &ParseError{f, "bad IPSECKEY GatewayA", l}, ""
2101 + }
2102 + case 2:
2103 + rr.GatewayAAAA = net.ParseIP(l.token)
2104 + if rr.GatewayAAAA == nil {
2105 + return nil, &ParseError{f, "bad IPSECKEY GatewayAAAA", l}, ""
2106 + }
2107 + default:
2108 + return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, ""
2109 + }
2110 +
2111 + s, e, c1 := endingToString(c, "bad IPSECKEY PublicKey", f)
2112 + if e != nil {
2113 + return nil, e, c1
2114 + }
2115 + rr.PublicKey = s
2116 + return rr, nil, c1
2117 +}
2118 +
2119 +var typeToparserFunc = map[uint16]parserFunc{
2120 + TypeAAAA: parserFunc{setAAAA, false},
2121 + TypeAFSDB: parserFunc{setAFSDB, false},
2122 + TypeA: parserFunc{setA, false},
2123 + TypeCDS: parserFunc{setCDS, true},
2124 + TypeCDNSKEY: parserFunc{setCDNSKEY, true},
2125 + TypeCERT: parserFunc{setCERT, true},
2126 + TypeCNAME: parserFunc{setCNAME, false},
2127 + TypeDHCID: parserFunc{setDHCID, true},
2128 + TypeDLV: parserFunc{setDLV, true},
2129 + TypeDNAME: parserFunc{setDNAME, false},
2130 + TypeKEY: parserFunc{setKEY, true},
2131 + TypeDNSKEY: parserFunc{setDNSKEY, true},
2132 + TypeDS: parserFunc{setDS, true},
2133 + TypeEID: parserFunc{setEID, true},
2134 + TypeEUI48: parserFunc{setEUI48, false},
2135 + TypeEUI64: parserFunc{setEUI64, false},
2136 + TypeGID: parserFunc{setGID, false},
2137 + TypeGPOS: parserFunc{setGPOS, false},
2138 + TypeHINFO: parserFunc{setHINFO, false},
2139 + TypeHIP: parserFunc{setHIP, true},
2140 + TypeIPSECKEY: parserFunc{setIPSECKEY, true},
2141 + TypeKX: parserFunc{setKX, false},
2142 + TypeL32: parserFunc{setL32, false},
2143 + TypeL64: parserFunc{setL64, false},
2144 + TypeLOC: parserFunc{setLOC, true},
2145 + TypeLP: parserFunc{setLP, false},
2146 + TypeMB: parserFunc{setMB, false},
2147 + TypeMD: parserFunc{setMD, false},
2148 + TypeMF: parserFunc{setMF, false},
2149 + TypeMG: parserFunc{setMG, false},
2150 + TypeMINFO: parserFunc{setMINFO, false},
2151 + TypeMR: parserFunc{setMR, false},
2152 + TypeMX: parserFunc{setMX, false},
2153 + TypeNAPTR: parserFunc{setNAPTR, false},
2154 + TypeNID: parserFunc{setNID, false},
2155 + TypeNIMLOC: parserFunc{setNIMLOC, true},
2156 + TypeNINFO: parserFunc{setNINFO, true},
2157 + TypeNSAP: parserFunc{setNSAP, true},
2158 + TypeNSAPPTR: parserFunc{setNSAPPTR, false},
2159 + TypeNSEC3PARAM: parserFunc{setNSEC3PARAM, false},
2160 + TypeNSEC3: parserFunc{setNSEC3, true},
2161 + TypeNSEC: parserFunc{setNSEC, true},
2162 + TypeNS: parserFunc{setNS, false},
2163 + TypeOPENPGPKEY: parserFunc{setOPENPGPKEY, true},
2164 + TypePTR: parserFunc{setPTR, false},
2165 + TypePX: parserFunc{setPX, false},
2166 + TypeSIG: parserFunc{setSIG, true},
2167 + TypeRKEY: parserFunc{setRKEY, true},
2168 + TypeRP: parserFunc{setRP, false},
2169 + TypeRRSIG: parserFunc{setRRSIG, true},
2170 + TypeRT: parserFunc{setRT, false},
2171 + TypeSOA: parserFunc{setSOA, false},
2172 + TypeSPF: parserFunc{setSPF, true},
2173 + TypeSRV: parserFunc{setSRV, false},
2174 + TypeSSHFP: parserFunc{setSSHFP, false},
2175 + TypeTALINK: parserFunc{setTALINK, false},
2176 + TypeTA: parserFunc{setTA, true},
2177 + TypeTLSA: parserFunc{setTLSA, true},
2178 + TypeTXT: parserFunc{setTXT, true},
2179 + TypeUID: parserFunc{setUID, false},
2180 + TypeUINFO: parserFunc{setUINFO, true},
2181 + TypeURI: parserFunc{setURI, true},
2182 + TypeWKS: parserFunc{setWKS, true},
2183 + TypeX25: parserFunc{setX25, false},
2184 +}
p2p/discovery/mdns.go
+1 -1
@@ -11,7 +11,7 @@ import (
11 "sync"
12 "time"
13
14 - "github.com/hashicorp/mdns"
14 + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/mdns"
15 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
16 manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
17