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
+[](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