Browse code

Vendoring memberlist tag 0.1.0

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>

Flavio Crisciani authored on 2017/04/28 05:20:11
Showing 37 changed files
... ...
@@ -29,7 +29,9 @@ github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
29 29
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
30 30
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
31 31
 github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
32
-github.com/hashicorp/memberlist 88ac4de0d1a0ca6def284b571342db3b777a4c37
32
+github.com/hashicorp/memberlist v0.1.0
33
+github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
34
+github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
33 35
 github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
34 36
 github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
35 37
 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
36 38
new file mode 100644
... ...
@@ -0,0 +1,373 @@
0
+Mozilla Public License Version 2.0
1
+==================================
2
+
3
+1. Definitions
4
+--------------
5
+
6
+1.1. "Contributor"
7
+    means each individual or legal entity that creates, contributes to
8
+    the creation of, or owns Covered Software.
9
+
10
+1.2. "Contributor Version"
11
+    means the combination of the Contributions of others (if any) used
12
+    by a Contributor and that particular Contributor's Contribution.
13
+
14
+1.3. "Contribution"
15
+    means Covered Software of a particular Contributor.
16
+
17
+1.4. "Covered Software"
18
+    means Source Code Form to which the initial Contributor has attached
19
+    the notice in Exhibit A, the Executable Form of such Source Code
20
+    Form, and Modifications of such Source Code Form, in each case
21
+    including portions thereof.
22
+
23
+1.5. "Incompatible With Secondary Licenses"
24
+    means
25
+
26
+    (a) that the initial Contributor has attached the notice described
27
+        in Exhibit B to the Covered Software; or
28
+
29
+    (b) that the Covered Software was made available under the terms of
30
+        version 1.1 or earlier of the License, but not also under the
31
+        terms of a Secondary License.
32
+
33
+1.6. "Executable Form"
34
+    means any form of the work other than Source Code Form.
35
+
36
+1.7. "Larger Work"
37
+    means a work that combines Covered Software with other material, in
38
+    a separate file or files, that is not Covered Software.
39
+
40
+1.8. "License"
41
+    means this document.
42
+
43
+1.9. "Licensable"
44
+    means having the right to grant, to the maximum extent possible,
45
+    whether at the time of the initial grant or subsequently, any and
46
+    all of the rights conveyed by this License.
47
+
48
+1.10. "Modifications"
49
+    means any of the following:
50
+
51
+    (a) any file in Source Code Form that results from an addition to,
52
+        deletion from, or modification of the contents of Covered
53
+        Software; or
54
+
55
+    (b) any new file in Source Code Form that contains any Covered
56
+        Software.
57
+
58
+1.11. "Patent Claims" of a Contributor
59
+    means any patent claim(s), including without limitation, method,
60
+    process, and apparatus claims, in any patent Licensable by such
61
+    Contributor that would be infringed, but for the grant of the
62
+    License, by the making, using, selling, offering for sale, having
63
+    made, import, or transfer of either its Contributions or its
64
+    Contributor Version.
65
+
66
+1.12. "Secondary License"
67
+    means either the GNU General Public License, Version 2.0, the GNU
68
+    Lesser General Public License, Version 2.1, the GNU Affero General
69
+    Public License, Version 3.0, or any later versions of those
70
+    licenses.
71
+
72
+1.13. "Source Code Form"
73
+    means the form of the work preferred for making modifications.
74
+
75
+1.14. "You" (or "Your")
76
+    means an individual or a legal entity exercising rights under this
77
+    License. For legal entities, "You" includes any entity that
78
+    controls, is controlled by, or is under common control with You. For
79
+    purposes of this definition, "control" means (a) the power, direct
80
+    or indirect, to cause the direction or management of such entity,
81
+    whether by contract or otherwise, or (b) ownership of more than
82
+    fifty percent (50%) of the outstanding shares or beneficial
83
+    ownership of such entity.
84
+
85
+2. License Grants and Conditions
86
+--------------------------------
87
+
88
+2.1. Grants
89
+
90
+Each Contributor hereby grants You a world-wide, royalty-free,
91
+non-exclusive license:
92
+
93
+(a) under intellectual property rights (other than patent or trademark)
94
+    Licensable by such Contributor to use, reproduce, make available,
95
+    modify, display, perform, distribute, and otherwise exploit its
96
+    Contributions, either on an unmodified basis, with Modifications, or
97
+    as part of a Larger Work; and
98
+
99
+(b) under Patent Claims of such Contributor to make, use, sell, offer
100
+    for sale, have made, import, and otherwise transfer either its
101
+    Contributions or its Contributor Version.
102
+
103
+2.2. Effective Date
104
+
105
+The licenses granted in Section 2.1 with respect to any Contribution
106
+become effective for each Contribution on the date the Contributor first
107
+distributes such Contribution.
108
+
109
+2.3. Limitations on Grant Scope
110
+
111
+The licenses granted in this Section 2 are the only rights granted under
112
+this License. No additional rights or licenses will be implied from the
113
+distribution or licensing of Covered Software under this License.
114
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
115
+Contributor:
116
+
117
+(a) for any code that a Contributor has removed from Covered Software;
118
+    or
119
+
120
+(b) for infringements caused by: (i) Your and any other third party's
121
+    modifications of Covered Software, or (ii) the combination of its
122
+    Contributions with other software (except as part of its Contributor
123
+    Version); or
124
+
125
+(c) under Patent Claims infringed by Covered Software in the absence of
126
+    its Contributions.
127
+
128
+This License does not grant any rights in the trademarks, service marks,
129
+or logos of any Contributor (except as may be necessary to comply with
130
+the notice requirements in Section 3.4).
131
+
132
+2.4. Subsequent Licenses
133
+
134
+No Contributor makes additional grants as a result of Your choice to
135
+distribute the Covered Software under a subsequent version of this
136
+License (see Section 10.2) or under the terms of a Secondary License (if
137
+permitted under the terms of Section 3.3).
138
+
139
+2.5. Representation
140
+
141
+Each Contributor represents that the Contributor believes its
142
+Contributions are its original creation(s) or it has sufficient rights
143
+to grant the rights to its Contributions conveyed by this License.
144
+
145
+2.6. Fair Use
146
+
147
+This License is not intended to limit any rights You have under
148
+applicable copyright doctrines of fair use, fair dealing, or other
149
+equivalents.
150
+
151
+2.7. Conditions
152
+
153
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
154
+in Section 2.1.
155
+
156
+3. Responsibilities
157
+-------------------
158
+
159
+3.1. Distribution of Source Form
160
+
161
+All distribution of Covered Software in Source Code Form, including any
162
+Modifications that You create or to which You contribute, must be under
163
+the terms of this License. You must inform recipients that the Source
164
+Code Form of the Covered Software is governed by the terms of this
165
+License, and how they can obtain a copy of this License. You may not
166
+attempt to alter or restrict the recipients' rights in the Source Code
167
+Form.
168
+
169
+3.2. Distribution of Executable Form
170
+
171
+If You distribute Covered Software in Executable Form then:
172
+
173
+(a) such Covered Software must also be made available in Source Code
174
+    Form, as described in Section 3.1, and You must inform recipients of
175
+    the Executable Form how they can obtain a copy of such Source Code
176
+    Form by reasonable means in a timely manner, at a charge no more
177
+    than the cost of distribution to the recipient; and
178
+
179
+(b) You may distribute such Executable Form under the terms of this
180
+    License, or sublicense it under different terms, provided that the
181
+    license for the Executable Form does not attempt to limit or alter
182
+    the recipients' rights in the Source Code Form under this License.
183
+
184
+3.3. Distribution of a Larger Work
185
+
186
+You may create and distribute a Larger Work under terms of Your choice,
187
+provided that You also comply with the requirements of this License for
188
+the Covered Software. If the Larger Work is a combination of Covered
189
+Software with a work governed by one or more Secondary Licenses, and the
190
+Covered Software is not Incompatible With Secondary Licenses, this
191
+License permits You to additionally distribute such Covered Software
192
+under the terms of such Secondary License(s), so that the recipient of
193
+the Larger Work may, at their option, further distribute the Covered
194
+Software under the terms of either this License or such Secondary
195
+License(s).
196
+
197
+3.4. Notices
198
+
199
+You may not remove or alter the substance of any license notices
200
+(including copyright notices, patent notices, disclaimers of warranty,
201
+or limitations of liability) contained within the Source Code Form of
202
+the Covered Software, except that You may alter any license notices to
203
+the extent required to remedy known factual inaccuracies.
204
+
205
+3.5. Application of Additional Terms
206
+
207
+You may choose to offer, and to charge a fee for, warranty, support,
208
+indemnity or liability obligations to one or more recipients of Covered
209
+Software. However, You may do so only on Your own behalf, and not on
210
+behalf of any Contributor. You must make it absolutely clear that any
211
+such warranty, support, indemnity, or liability obligation is offered by
212
+You alone, and You hereby agree to indemnify every Contributor for any
213
+liability incurred by such Contributor as a result of warranty, support,
214
+indemnity or liability terms You offer. You may include additional
215
+disclaimers of warranty and limitations of liability specific to any
216
+jurisdiction.
217
+
218
+4. Inability to Comply Due to Statute or Regulation
219
+---------------------------------------------------
220
+
221
+If it is impossible for You to comply with any of the terms of this
222
+License with respect to some or all of the Covered Software due to
223
+statute, judicial order, or regulation then You must: (a) comply with
224
+the terms of this License to the maximum extent possible; and (b)
225
+describe the limitations and the code they affect. Such description must
226
+be placed in a text file included with all distributions of the Covered
227
+Software under this License. Except to the extent prohibited by statute
228
+or regulation, such description must be sufficiently detailed for a
229
+recipient of ordinary skill to be able to understand it.
230
+
231
+5. Termination
232
+--------------
233
+
234
+5.1. The rights granted under this License will terminate automatically
235
+if You fail to comply with any of its terms. However, if You become
236
+compliant, then the rights granted under this License from a particular
237
+Contributor are reinstated (a) provisionally, unless and until such
238
+Contributor explicitly and finally terminates Your grants, and (b) on an
239
+ongoing basis, if such Contributor fails to notify You of the
240
+non-compliance by some reasonable means prior to 60 days after You have
241
+come back into compliance. Moreover, Your grants from a particular
242
+Contributor are reinstated on an ongoing basis if such Contributor
243
+notifies You of the non-compliance by some reasonable means, this is the
244
+first time You have received notice of non-compliance with this License
245
+from such Contributor, and You become compliant prior to 30 days after
246
+Your receipt of the notice.
247
+
248
+5.2. If You initiate litigation against any entity by asserting a patent
249
+infringement claim (excluding declaratory judgment actions,
250
+counter-claims, and cross-claims) alleging that a Contributor Version
251
+directly or indirectly infringes any patent, then the rights granted to
252
+You by any and all Contributors for the Covered Software under Section
253
+2.1 of this License shall terminate.
254
+
255
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
256
+end user license agreements (excluding distributors and resellers) which
257
+have been validly granted by You or Your distributors under this License
258
+prior to termination shall survive termination.
259
+
260
+************************************************************************
261
+*                                                                      *
262
+*  6. Disclaimer of Warranty                                           *
263
+*  -------------------------                                           *
264
+*                                                                      *
265
+*  Covered Software is provided under this License on an "as is"       *
266
+*  basis, without warranty of any kind, either expressed, implied, or  *
267
+*  statutory, including, without limitation, warranties that the       *
268
+*  Covered Software is free of defects, merchantable, fit for a        *
269
+*  particular purpose or non-infringing. The entire risk as to the     *
270
+*  quality and performance of the Covered Software is with You.        *
271
+*  Should any Covered Software prove defective in any respect, You     *
272
+*  (not any Contributor) assume the cost of any necessary servicing,   *
273
+*  repair, or correction. This disclaimer of warranty constitutes an   *
274
+*  essential part of this License. No use of any Covered Software is   *
275
+*  authorized under this License except under this disclaimer.         *
276
+*                                                                      *
277
+************************************************************************
278
+
279
+************************************************************************
280
+*                                                                      *
281
+*  7. Limitation of Liability                                          *
282
+*  --------------------------                                          *
283
+*                                                                      *
284
+*  Under no circumstances and under no legal theory, whether tort      *
285
+*  (including negligence), contract, or otherwise, shall any           *
286
+*  Contributor, or anyone who distributes Covered Software as          *
287
+*  permitted above, be liable to You for any direct, indirect,         *
288
+*  special, incidental, or consequential damages of any character      *
289
+*  including, without limitation, damages for lost profits, loss of    *
290
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
291
+*  and all other commercial damages or losses, even if such party      *
292
+*  shall have been informed of the possibility of such damages. This   *
293
+*  limitation of liability shall not apply to liability for death or   *
294
+*  personal injury resulting from such party's negligence to the       *
295
+*  extent applicable law prohibits such limitation. Some               *
296
+*  jurisdictions do not allow the exclusion or limitation of           *
297
+*  incidental or consequential damages, so this exclusion and          *
298
+*  limitation may not apply to You.                                    *
299
+*                                                                      *
300
+************************************************************************
301
+
302
+8. Litigation
303
+-------------
304
+
305
+Any litigation relating to this License may be brought only in the
306
+courts of a jurisdiction where the defendant maintains its principal
307
+place of business and such litigation shall be governed by laws of that
308
+jurisdiction, without reference to its conflict-of-law provisions.
309
+Nothing in this Section shall prevent a party's ability to bring
310
+cross-claims or counter-claims.
311
+
312
+9. Miscellaneous
313
+----------------
314
+
315
+This License represents the complete agreement concerning the subject
316
+matter hereof. If any provision of this License is held to be
317
+unenforceable, such provision shall be reformed only to the extent
318
+necessary to make it enforceable. Any law or regulation which provides
319
+that the language of a contract shall be construed against the drafter
320
+shall not be used to construe this License against a Contributor.
321
+
322
+10. Versions of the License
323
+---------------------------
324
+
325
+10.1. New Versions
326
+
327
+Mozilla Foundation is the license steward. Except as provided in Section
328
+10.3, no one other than the license steward has the right to modify or
329
+publish new versions of this License. Each version will be given a
330
+distinguishing version number.
331
+
332
+10.2. Effect of New Versions
333
+
334
+You may distribute the Covered Software under the terms of the version
335
+of the License under which You originally received the Covered Software,
336
+or under the terms of any subsequent version published by the license
337
+steward.
338
+
339
+10.3. Modified Versions
340
+
341
+If you create software not governed by this License, and you want to
342
+create a new license for such software, you may create and use a
343
+modified version of this License if you rename the license and remove
344
+any references to the name of the license steward (except to note that
345
+such modified license differs from this License).
346
+
347
+10.4. Distributing Source Code Form that is Incompatible With Secondary
348
+Licenses
349
+
350
+If You choose to distribute Source Code Form that is Incompatible With
351
+Secondary Licenses under the terms of this version of the License, the
352
+notice described in Exhibit B of this License must be attached.
353
+
354
+Exhibit A - Source Code Form License Notice
355
+-------------------------------------------
356
+
357
+  This Source Code Form is subject to the terms of the Mozilla Public
358
+  License, v. 2.0. If a copy of the MPL was not distributed with this
359
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
360
+
361
+If it is not possible or desirable to put the notice in a particular
362
+file, then You may include the notice in a location (such as a LICENSE
363
+file in a relevant directory) where a recipient would be likely to look
364
+for such a notice.
365
+
366
+You may add additional accurate notices of copyright ownership.
367
+
368
+Exhibit B - "Incompatible With Secondary Licenses" Notice
369
+---------------------------------------------------------
370
+
371
+  This Source Code Form is "Incompatible With Secondary Licenses", as
372
+  defined by the Mozilla Public License, v. 2.0.
0 373
new file mode 100644
... ...
@@ -0,0 +1,118 @@
0
+# go-sockaddr
1
+
2
+## `sockaddr` Library
3
+
4
+Socket address convenience functions for Go.  `go-sockaddr` is a convenience
5
+library that makes doing the right thing with IP addresses easy.  `go-sockaddr`
6
+is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family
7
+of `sockaddr_t` types (see below for an ascii diagram).  Library documentation
8
+is available
9
+at
10
+[https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr).
11
+The primary intent of the library was to make it possible to define heuristics
12
+for selecting the correct IP addresses when a configuration is evaluated at
13
+runtime.  See
14
+the
15
+[docs](https://godoc.org/github.com/hashicorp/go-sockaddr),
16
+[`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template),
17
+tests,
18
+and
19
+[CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
20
+for details and hints as to how to use this library.
21
+
22
+For example, with this library it is possible to find an IP address that:
23
+
24
+* is attached to a default route
25
+  ([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces))
26
+* is contained within a CIDR block ([`IfByNetwork()`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork))
27
+* is an RFC1918 address
28
+  ([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
29
+* is ordered
30
+  ([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where
31
+  `args` includes, but is not limited
32
+  to,
33
+  [`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType),
34
+  [`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize))
35
+* excludes all IPv6 addresses
36
+  ([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType))
37
+* is larger than a `/32`
38
+  ([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize))
39
+* is not on a `down` interface
40
+  ([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs))
41
+* preferences an IPv6 address over an IPv4 address
42
+  ([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) +
43
+  [`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and
44
+* excludes any IP in RFC6890 address
45
+  ([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
46
+
47
+Or any combination or variation therein.
48
+
49
+There are also a few simple helper functions such as `GetPublicIP` and
50
+`GetPrivateIP` which both return strings and select the first public or private
51
+IP address on the default interface, respectively.  Similarly, there is also a
52
+helper function called `GetInterfaceIP` which returns the first usable IP
53
+address on the named interface.
54
+
55
+## `sockaddr` CLI
56
+
57
+Given the possible complexity of the `sockaddr` library, there is a CLI utility
58
+that accompanies the library, also
59
+called
60
+[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr).
61
+The
62
+[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
63
+utility exposes nearly all of the functionality of the library and can be used
64
+either as an administrative tool or testing tool.  To install
65
+the
66
+[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr),
67
+run:
68
+
69
+```text
70
+$ go get -u github.com/hashicorp/go-sockaddr/cmd/sockaddr
71
+```
72
+
73
+If you're familiar with UNIX's `sockaddr` struct's, the following diagram
74
+mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and
75
+interfaces will be helpful:
76
+
77
+```
78
++-------------------------------------------------------+
79
+|                                                       |
80
+|                        sockaddr                       |
81
+|                        SockAddr                       |
82
+|                                                       |
83
+| +--------------+ +----------------------------------+ |
84
+| | sockaddr_un  | |                                  | |
85
+| | SockAddrUnix | |           sockaddr_in{,6}        | |
86
+| +--------------+ |                IPAddr            | |
87
+|                  |                                  | |
88
+|                  | +-------------+ +--------------+ | |
89
+|                  | | sockaddr_in | | sockaddr_in6 | | |
90
+|                  | |   IPv4Addr  | |   IPv6Addr   | | |
91
+|                  | +-------------+ +--------------+ | |
92
+|                  |                                  | |
93
+|                  +----------------------------------+ |
94
+|                                                       |
95
++-------------------------------------------------------+
96
+```
97
+
98
+## Inspiration and Design
99
+
100
+There were many subtle inspirations that led to this design, but the most direct
101
+inspiration for the filtering syntax was
102
+OpenBSD's
103
+[`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall
104
+syntax that lets you select the first IP address on a given named interface.
105
+The original problem stemmed from:
106
+
107
+* needing to create immutable images using [Packer](https://www.packer.io) that
108
+  ran the [Consul](https://www.consul.io) process (Consul can only use one IP
109
+  address at a time);
110
+* images that may or may not have multiple interfaces or IP addresses at
111
+  runtime; and
112
+* we didn't want to rely on configuration management to render out the correct
113
+  IP address if the VM image was being used in an auto-scaling group.
114
+
115
+Instead we needed some way to codify a heuristic that would correctly select the
116
+right IP address but the input parameters were not known when the image was
117
+created.
0 118
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+/*
1
+Package sockaddr is a Go implementation of the UNIX socket family data types and
2
+related helper functions.
3
+*/
4
+package sockaddr
0 5
new file mode 100644
... ...
@@ -0,0 +1,126 @@
0
+package sockaddr
1
+
2
+// ifAddrAttrMap is a map of the IfAddr type-specific attributes.
3
+var ifAddrAttrMap map[AttrName]func(IfAddr) string
4
+var ifAddrAttrs []AttrName
5
+
6
+func init() {
7
+	ifAddrAttrInit()
8
+}
9
+
10
+// GetPrivateIP returns a string with a single IP address that is part of RFC
11
+// 6890 and has a default route.  If the system can't determine its IP address
12
+// or find an RFC 6890 IP address, an empty string will be returned instead.
13
+// This function is the `eval` equivalent of:
14
+//
15
+// ```
16
+// $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}'
17
+/// ```
18
+func GetPrivateIP() (string, error) {
19
+	privateIfs, err := GetPrivateInterfaces()
20
+	if err != nil {
21
+		return "", err
22
+	}
23
+	if len(privateIfs) < 1 {
24
+		return "", nil
25
+	}
26
+
27
+	ifAddr := privateIfs[0]
28
+	ip := *ToIPAddr(ifAddr.SockAddr)
29
+	return ip.NetIP().String(), nil
30
+}
31
+
32
+// GetPublicIP returns a string with a single IP address that is NOT part of RFC
33
+// 6890 and has a default route.  If the system can't determine its IP address
34
+// or find a non RFC 6890 IP address, an empty string will be returned instead.
35
+// This function is the `eval` equivalent of:
36
+//
37
+// ```
38
+// $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}'
39
+/// ```
40
+func GetPublicIP() (string, error) {
41
+	publicIfs, err := GetPublicInterfaces()
42
+	if err != nil {
43
+		return "", err
44
+	} else if len(publicIfs) < 1 {
45
+		return "", nil
46
+	}
47
+
48
+	ifAddr := publicIfs[0]
49
+	ip := *ToIPAddr(ifAddr.SockAddr)
50
+	return ip.NetIP().String(), nil
51
+}
52
+
53
+// GetInterfaceIP returns a string with a single IP address sorted by the size
54
+// of the network (i.e. IP addresses with a smaller netmask, larger network
55
+// size, are sorted first).  This function is the `eval` equivalent of:
56
+//
57
+// ```
58
+// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <<ARG>> | sort "type,size" | include "flag" "forwardable" | attr "address" }}'
59
+/// ```
60
+func GetInterfaceIP(namedIfRE string) (string, error) {
61
+	ifAddrs, err := GetAllInterfaces()
62
+	if err != nil {
63
+		return "", err
64
+	}
65
+
66
+	ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
67
+	if err != nil {
68
+		return "", err
69
+	}
70
+
71
+	ifAddrs, _, err = IfByFlag("forwardable", ifAddrs)
72
+	if err != nil {
73
+		return "", err
74
+	}
75
+
76
+	ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
77
+	if err != nil {
78
+		return "", err
79
+	}
80
+
81
+	if len(ifAddrs) == 0 {
82
+		return "", err
83
+	}
84
+
85
+	ip := ToIPAddr(ifAddrs[0].SockAddr)
86
+	if ip == nil {
87
+		return "", err
88
+	}
89
+
90
+	return IPAddrAttr(*ip, "address"), nil
91
+}
92
+
93
+// IfAddrAttrs returns a list of attributes supported by the IfAddr type
94
+func IfAddrAttrs() []AttrName {
95
+	return ifAddrAttrs
96
+}
97
+
98
+// IfAddrAttr returns a string representation of an attribute for the given
99
+// IfAddr.
100
+func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string {
101
+	fn, found := ifAddrAttrMap[attrName]
102
+	if !found {
103
+		return ""
104
+	}
105
+
106
+	return fn(ifAddr)
107
+}
108
+
109
+// ifAddrAttrInit is called once at init()
110
+func ifAddrAttrInit() {
111
+	// Sorted for human readability
112
+	ifAddrAttrs = []AttrName{
113
+		"flags",
114
+		"name",
115
+	}
116
+
117
+	ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{
118
+		"flags": func(ifAddr IfAddr) string {
119
+			return ifAddr.Interface.Flags.String()
120
+		},
121
+		"name": func(ifAddr IfAddr) string {
122
+			return ifAddr.Interface.Name
123
+		},
124
+	}
125
+}
0 126
new file mode 100644
... ...
@@ -0,0 +1,969 @@
0
+package sockaddr
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"net"
6
+	"regexp"
7
+	"sort"
8
+	"strconv"
9
+	"strings"
10
+)
11
+
12
+// IfAddrs is a slice of IfAddr
13
+type IfAddrs []IfAddr
14
+
15
+func (ifs IfAddrs) Len() int { return len(ifs) }
16
+
17
+// CmpIfFunc is the function signature that must be met to be used in the
18
+// OrderedIfAddrBy multiIfAddrSorter
19
+type CmpIfAddrFunc func(p1, p2 *IfAddr) int
20
+
21
+// multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within.
22
+type multiIfAddrSorter struct {
23
+	ifAddrs IfAddrs
24
+	cmp     []CmpIfAddrFunc
25
+}
26
+
27
+// Sort sorts the argument slice according to the Cmp functions passed to
28
+// OrderedIfAddrBy.
29
+func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) {
30
+	ms.ifAddrs = ifAddrs
31
+	sort.Sort(ms)
32
+}
33
+
34
+// OrderedIfAddrBy sorts SockAddr by the list of sort function pointers.
35
+func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter {
36
+	return &multiIfAddrSorter{
37
+		cmp: cmpFuncs,
38
+	}
39
+}
40
+
41
+// Len is part of sort.Interface.
42
+func (ms *multiIfAddrSorter) Len() int {
43
+	return len(ms.ifAddrs)
44
+}
45
+
46
+// Less is part of sort.Interface. It is implemented by looping along the Cmp()
47
+// functions until it finds a comparison that is either less than or greater
48
+// than.  A return value of 0 defers sorting to the next function in the
49
+// multisorter (which means the results of sorting may leave the resutls in a
50
+// non-deterministic order).
51
+func (ms *multiIfAddrSorter) Less(i, j int) bool {
52
+	p, q := &ms.ifAddrs[i], &ms.ifAddrs[j]
53
+	// Try all but the last comparison.
54
+	var k int
55
+	for k = 0; k < len(ms.cmp)-1; k++ {
56
+		cmp := ms.cmp[k]
57
+		x := cmp(p, q)
58
+		switch x {
59
+		case -1:
60
+			// p < q, so we have a decision.
61
+			return true
62
+		case 1:
63
+			// p > q, so we have a decision.
64
+			return false
65
+		}
66
+		// p == q; try the next comparison.
67
+	}
68
+	// All comparisons to here said "equal", so just return whatever the
69
+	// final comparison reports.
70
+	switch ms.cmp[k](p, q) {
71
+	case -1:
72
+		return true
73
+	case 1:
74
+		return false
75
+	default:
76
+		// Still a tie! Now what?
77
+		return false
78
+		panic("undefined sort order for remaining items in the list")
79
+	}
80
+}
81
+
82
+// Swap is part of sort.Interface.
83
+func (ms *multiIfAddrSorter) Swap(i, j int) {
84
+	ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i]
85
+}
86
+
87
+// AscIfAddress is a sorting function to sort IfAddrs by their respective
88
+// address type.  Non-equal types are deferred in the sort.
89
+func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int {
90
+	return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
91
+}
92
+
93
+// AscIfName is a sorting function to sort IfAddrs by their interface names.
94
+func AscIfName(p1Ptr, p2Ptr *IfAddr) int {
95
+	return strings.Compare(p1Ptr.Name, p2Ptr.Name)
96
+}
97
+
98
+// AscIfNetworkSize is a sorting function to sort IfAddrs by their respective
99
+// network mask size.
100
+func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
101
+	return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
102
+}
103
+
104
+// AscIfPort is a sorting function to sort IfAddrs by their respective
105
+// port type.  Non-equal types are deferred in the sort.
106
+func AscIfPort(p1Ptr, p2Ptr *IfAddr) int {
107
+	return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
108
+}
109
+
110
+// AscIfPrivate is a sorting function to sort IfAddrs by "private" values before
111
+// "public" values.  Both IPv4 and IPv6 are compared against RFC6890 (RFC6890
112
+// includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6
113
+// includes RFC4193).
114
+func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
115
+	return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
116
+}
117
+
118
+// AscIfType is a sorting function to sort IfAddrs by their respective address
119
+// type.  Non-equal types are deferred in the sort.
120
+func AscIfType(p1Ptr, p2Ptr *IfAddr) int {
121
+	return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
122
+}
123
+
124
+// DescIfAddress is identical to AscIfAddress but reverse ordered.
125
+func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int {
126
+	return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
127
+}
128
+
129
+// DescIfName is identical to AscIfName but reverse ordered.
130
+func DescIfName(p1Ptr, p2Ptr *IfAddr) int {
131
+	return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name)
132
+}
133
+
134
+// DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered.
135
+func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
136
+	return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
137
+}
138
+
139
+// DescIfPort is identical to AscIfPort but reverse ordered.
140
+func DescIfPort(p1Ptr, p2Ptr *IfAddr) int {
141
+	return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
142
+}
143
+
144
+// DescIfPrivate is identical to AscIfPrivate but reverse ordered.
145
+func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
146
+	return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
147
+}
148
+
149
+// DescIfType is identical to AscIfType but reverse ordered.
150
+func DescIfType(p1Ptr, p2Ptr *IfAddr) int {
151
+	return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
152
+}
153
+
154
+// FilterIfByType filters IfAddrs and returns a list of the matching type
155
+func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) {
156
+	excludedIfs = make(IfAddrs, 0, len(ifAddrs))
157
+	matchedIfs = make(IfAddrs, 0, len(ifAddrs))
158
+
159
+	for _, ifAddr := range ifAddrs {
160
+		if ifAddr.SockAddr.Type()&type_ != 0 {
161
+			matchedIfs = append(matchedIfs, ifAddr)
162
+		} else {
163
+			excludedIfs = append(excludedIfs, ifAddr)
164
+		}
165
+	}
166
+	return matchedIfs, excludedIfs
167
+}
168
+
169
+// IfAttr forwards the selector to IfAttr.Attr() for resolution.  If there is
170
+// more than one IfAddr, only the first IfAddr is used.
171
+func IfAttr(selectorName string, ifAddrs IfAddrs) (string, error) {
172
+	if len(ifAddrs) == 0 {
173
+		return "", nil
174
+	}
175
+
176
+	attrName := AttrName(strings.ToLower(selectorName))
177
+	attrVal, err := ifAddrs[0].Attr(attrName)
178
+	return attrVal, err
179
+}
180
+
181
+// GetAllInterfaces iterates over all available network interfaces and finds all
182
+// available IP addresses on each interface and converts them to
183
+// sockaddr.IPAddrs, and returning the result as an array of IfAddr.
184
+func GetAllInterfaces() (IfAddrs, error) {
185
+	ifs, err := net.Interfaces()
186
+	if err != nil {
187
+		return nil, err
188
+	}
189
+
190
+	ifAddrs := make(IfAddrs, 0, len(ifs))
191
+	for _, intf := range ifs {
192
+		addrs, err := intf.Addrs()
193
+		if err != nil {
194
+			return nil, err
195
+		}
196
+
197
+		for _, addr := range addrs {
198
+			var ipAddr IPAddr
199
+			ipAddr, err = NewIPAddr(addr.String())
200
+			if err != nil {
201
+				return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String())
202
+			}
203
+
204
+			ifAddr := IfAddr{
205
+				SockAddr:  ipAddr,
206
+				Interface: intf,
207
+			}
208
+			ifAddrs = append(ifAddrs, ifAddr)
209
+		}
210
+	}
211
+
212
+	return ifAddrs, nil
213
+}
214
+
215
+// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default
216
+// route.
217
+func GetDefaultInterfaces() (IfAddrs, error) {
218
+	ri, err := NewRouteInfo()
219
+	if err != nil {
220
+		return nil, err
221
+	}
222
+
223
+	defaultIfName, err := ri.GetDefaultInterfaceName()
224
+	if err != nil {
225
+		return nil, err
226
+	}
227
+
228
+	var defaultIfs, ifAddrs IfAddrs
229
+	ifAddrs, err = GetAllInterfaces()
230
+	for _, ifAddr := range ifAddrs {
231
+		if ifAddr.Name == defaultIfName {
232
+			defaultIfs = append(defaultIfs, ifAddr)
233
+		}
234
+	}
235
+
236
+	return defaultIfs, nil
237
+}
238
+
239
+// GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a
240
+// default route.  If the system can't determine its IP address or find an RFC
241
+// 6890 IP address, an empty IfAddrs will be returned instead.  This function is
242
+// the `eval` equivalent of:
243
+//
244
+// ```
245
+// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | include "RFC" "6890" }}'
246
+/// ```
247
+func GetPrivateInterfaces() (IfAddrs, error) {
248
+	privateIfs, err := GetDefaultInterfaces()
249
+	if err != nil {
250
+		return IfAddrs{}, err
251
+	}
252
+	if len(privateIfs) == 0 {
253
+		return IfAddrs{}, nil
254
+	}
255
+
256
+	privateIfs, _ = FilterIfByType(privateIfs, TypeIP)
257
+	if len(privateIfs) == 0 {
258
+		return IfAddrs{}, nil
259
+	}
260
+
261
+	privateIfs, _, err = IfByFlag("forwardable|up", privateIfs)
262
+	if err != nil {
263
+		return IfAddrs{}, err
264
+	}
265
+	if len(privateIfs) == 0 {
266
+		return IfAddrs{}, nil
267
+	}
268
+
269
+	OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(privateIfs)
270
+
271
+	privateIfs, _, err = IfByRFC("6890", privateIfs)
272
+	if err != nil {
273
+		return IfAddrs{}, err
274
+	} else if len(privateIfs) == 0 {
275
+		return IfAddrs{}, nil
276
+	}
277
+
278
+	return privateIfs, nil
279
+}
280
+
281
+// GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a
282
+// default route.  If the system can't determine its IP address or find a non
283
+// RFC 6890 IP address, an empty IfAddrs will be returned instead.  This
284
+// function is the `eval` equivalent of:
285
+//
286
+// ```
287
+// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | exclude "RFC" "6890" }}'
288
+/// ```
289
+func GetPublicInterfaces() (IfAddrs, error) {
290
+	publicIfs, err := GetDefaultInterfaces()
291
+	if err != nil {
292
+		return IfAddrs{}, err
293
+	}
294
+	if len(publicIfs) == 0 {
295
+		return IfAddrs{}, nil
296
+	}
297
+
298
+	publicIfs, _ = FilterIfByType(publicIfs, TypeIP)
299
+	if len(publicIfs) == 0 {
300
+		return IfAddrs{}, nil
301
+	}
302
+
303
+	publicIfs, _, err = IfByFlag("forwardable|up", publicIfs)
304
+	if err != nil {
305
+		return IfAddrs{}, err
306
+	}
307
+	if len(publicIfs) == 0 {
308
+		return IfAddrs{}, nil
309
+	}
310
+
311
+	OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(publicIfs)
312
+
313
+	_, publicIfs, err = IfByRFC("6890", publicIfs)
314
+	if err != nil {
315
+		return IfAddrs{}, err
316
+	} else if len(publicIfs) == 0 {
317
+		return IfAddrs{}, nil
318
+	}
319
+
320
+	return publicIfs, nil
321
+}
322
+
323
+// IfByAddress returns a list of matched and non-matched IfAddrs, or an error if
324
+// the regexp fails to compile.
325
+func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
326
+	re, err := regexp.Compile(inputRe)
327
+	if err != nil {
328
+		return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err)
329
+	}
330
+
331
+	matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
332
+	excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
333
+	for _, addr := range ifAddrs {
334
+		if re.MatchString(addr.SockAddr.String()) {
335
+			matchedAddrs = append(matchedAddrs, addr)
336
+		} else {
337
+			excludedAddrs = append(excludedAddrs, addr)
338
+		}
339
+	}
340
+
341
+	return matchedAddrs, excludedAddrs, nil
342
+}
343
+
344
+// IfByName returns a list of matched and non-matched IfAddrs, or an error if
345
+// the regexp fails to compile.
346
+func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
347
+	re, err := regexp.Compile(inputRe)
348
+	if err != nil {
349
+		return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err)
350
+	}
351
+
352
+	matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
353
+	excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
354
+	for _, addr := range ifAddrs {
355
+		if re.MatchString(addr.Name) {
356
+			matchedAddrs = append(matchedAddrs, addr)
357
+		} else {
358
+			excludedAddrs = append(excludedAddrs, addr)
359
+		}
360
+	}
361
+
362
+	return matchedAddrs, excludedAddrs, nil
363
+}
364
+
365
+// IfByPort returns a list of matched and non-matched IfAddrs, or an error if
366
+// the regexp fails to compile.
367
+func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
368
+	re, err := regexp.Compile(inputRe)
369
+	if err != nil {
370
+		return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err)
371
+	}
372
+
373
+	ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
374
+	matchedIfs = make(IfAddrs, 0, len(ipIfs))
375
+	excludedIfs = append(IfAddrs(nil), nonIfs...)
376
+	for _, addr := range ipIfs {
377
+		ipAddr := ToIPAddr(addr.SockAddr)
378
+		if ipAddr == nil {
379
+			continue
380
+		}
381
+
382
+		port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10)
383
+		if re.MatchString(port) {
384
+			matchedIfs = append(matchedIfs, addr)
385
+		} else {
386
+			excludedIfs = append(excludedIfs, addr)
387
+		}
388
+	}
389
+
390
+	return matchedIfs, excludedIfs, nil
391
+}
392
+
393
+// IfByRFC returns a list of matched and non-matched IfAddrs that contain the
394
+// relevant RFC-specified traits.
395
+func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
396
+	inputRFC, err := strconv.ParseUint(selectorParam, 10, 64)
397
+	if err != nil {
398
+		return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err)
399
+	}
400
+
401
+	matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs))
402
+	remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
403
+
404
+	rfcNetMap := KnownRFCs()
405
+	rfcNets, ok := rfcNetMap[uint(inputRFC)]
406
+	if !ok {
407
+		return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC)
408
+	}
409
+
410
+	for _, ifAddr := range ifAddrs {
411
+		var contained bool
412
+		for _, rfcNet := range rfcNets {
413
+			if rfcNet.Contains(ifAddr.SockAddr) {
414
+				matchedIfAddrs = append(matchedIfAddrs, ifAddr)
415
+				contained = true
416
+				break
417
+			}
418
+		}
419
+		if !contained {
420
+			remainingIfAddrs = append(remainingIfAddrs, ifAddr)
421
+		}
422
+	}
423
+
424
+	return matchedIfAddrs, remainingIfAddrs, nil
425
+}
426
+
427
+// IfByRFCs returns a list of matched and non-matched IfAddrs that contain the
428
+// relevant RFC-specified traits.  Multiple RFCs can be specified and separated
429
+// by the `|` symbol.  No protection is taken to ensure an IfAddr does not end
430
+// up in both the included and excluded list.
431
+func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
432
+	var includedIfs, excludedIfs IfAddrs
433
+	for _, rfcStr := range strings.Split(selectorParam, "|") {
434
+		includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs)
435
+		if err != nil {
436
+			return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err)
437
+		}
438
+		includedIfs = append(includedIfs, includedRFCIfs...)
439
+		excludedIfs = append(excludedIfs, excludedRFCIfs...)
440
+	}
441
+
442
+	return includedIfs, excludedIfs, nil
443
+}
444
+
445
+// IfByMaskSize returns a list of matched and non-matched IfAddrs that have the
446
+// matching mask size.
447
+func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
448
+	maskSize, err := strconv.ParseUint(selectorParam, 10, 64)
449
+	if err != nil {
450
+		return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err)
451
+	}
452
+
453
+	ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
454
+	matchedIfs = make(IfAddrs, 0, len(ipIfs))
455
+	excludedIfs = append(IfAddrs(nil), nonIfs...)
456
+	for _, addr := range ipIfs {
457
+		ipAddr := ToIPAddr(addr.SockAddr)
458
+		if ipAddr == nil {
459
+			return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String())
460
+		}
461
+
462
+		switch {
463
+		case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32:
464
+			return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize)
465
+		case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128:
466
+			return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize)
467
+		}
468
+
469
+		if (*ipAddr).Maskbits() == int(maskSize) {
470
+			matchedIfs = append(matchedIfs, addr)
471
+		} else {
472
+			excludedIfs = append(excludedIfs, addr)
473
+		}
474
+	}
475
+
476
+	return matchedIfs, excludedIfs, nil
477
+}
478
+
479
+// IfByType returns a list of matching and non-matching IfAddr that match the
480
+// specified type.  For instance:
481
+//
482
+// include "type" "IPv4,IPv6"
483
+//
484
+// will include any IfAddrs that is either an IPv4 or IPv6 address.  Any
485
+// addresses on those interfaces that don't match will be included in the
486
+// remainder results.
487
+func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
488
+	matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
489
+	remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
490
+
491
+	ifTypes := strings.Split(strings.ToLower(inputTypes), "|")
492
+	for _, ifType := range ifTypes {
493
+		switch ifType {
494
+		case "ip", "ipv4", "ipv6", "unix":
495
+			// Valid types
496
+		default:
497
+			return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes)
498
+		}
499
+	}
500
+
501
+	for _, ifAddr := range ifAddrs {
502
+		for _, ifType := range ifTypes {
503
+			var matched bool
504
+			switch {
505
+			case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0:
506
+				matched = true
507
+			case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0:
508
+				matched = true
509
+			case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0:
510
+				matched = true
511
+			case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0:
512
+				matched = true
513
+			}
514
+
515
+			if matched {
516
+				matchingIfAddrs = append(matchingIfAddrs, ifAddr)
517
+			} else {
518
+				remainingIfAddrs = append(remainingIfAddrs, ifAddr)
519
+			}
520
+		}
521
+	}
522
+
523
+	return matchingIfAddrs, remainingIfAddrs, nil
524
+}
525
+
526
+// IfByFlag returns a list of matching and non-matching IfAddrs that match the
527
+// specified type.  For instance:
528
+//
529
+// include "flag" "up,broadcast"
530
+//
531
+// will include any IfAddrs that have both the "up" and "broadcast" flags set.
532
+// Any addresses on those interfaces that don't match will be omitted from the
533
+// results.
534
+func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
535
+	matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
536
+	excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
537
+
538
+	var wantForwardable,
539
+		wantGlobalUnicast,
540
+		wantInterfaceLocalMulticast,
541
+		wantLinkLocalMulticast,
542
+		wantLinkLocalUnicast,
543
+		wantLoopback,
544
+		wantMulticast,
545
+		wantUnspecified bool
546
+	var ifFlags net.Flags
547
+	var checkFlags, checkAttrs bool
548
+	for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") {
549
+		switch flagName {
550
+		case "broadcast":
551
+			checkFlags = true
552
+			ifFlags = ifFlags | net.FlagBroadcast
553
+		case "down":
554
+			checkFlags = true
555
+			ifFlags = (ifFlags &^ net.FlagUp)
556
+		case "forwardable":
557
+			checkAttrs = true
558
+			wantForwardable = true
559
+		case "global unicast":
560
+			checkAttrs = true
561
+			wantGlobalUnicast = true
562
+		case "interface-local multicast":
563
+			checkAttrs = true
564
+			wantInterfaceLocalMulticast = true
565
+		case "link-local multicast":
566
+			checkAttrs = true
567
+			wantLinkLocalMulticast = true
568
+		case "link-local unicast":
569
+			checkAttrs = true
570
+			wantLinkLocalUnicast = true
571
+		case "loopback":
572
+			checkAttrs = true
573
+			checkFlags = true
574
+			ifFlags = ifFlags | net.FlagLoopback
575
+			wantLoopback = true
576
+		case "multicast":
577
+			checkAttrs = true
578
+			checkFlags = true
579
+			ifFlags = ifFlags | net.FlagMulticast
580
+			wantMulticast = true
581
+		case "point-to-point":
582
+			checkFlags = true
583
+			ifFlags = ifFlags | net.FlagPointToPoint
584
+		case "unspecified":
585
+			checkAttrs = true
586
+			wantUnspecified = true
587
+		case "up":
588
+			checkFlags = true
589
+			ifFlags = ifFlags | net.FlagUp
590
+		default:
591
+			return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName)
592
+		}
593
+	}
594
+
595
+	for _, ifAddr := range ifAddrs {
596
+		var matched bool
597
+		if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags {
598
+			matched = true
599
+		}
600
+		if checkAttrs {
601
+			if ip := ToIPAddr(ifAddr.SockAddr); ip != nil {
602
+				netIP := (*ip).NetIP()
603
+				switch {
604
+				case wantGlobalUnicast && netIP.IsGlobalUnicast():
605
+					matched = true
606
+				case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast():
607
+					matched = true
608
+				case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast():
609
+					matched = true
610
+				case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast():
611
+					matched = true
612
+				case wantLoopback && netIP.IsLoopback():
613
+					matched = true
614
+				case wantMulticast && netIP.IsMulticast():
615
+					matched = true
616
+				case wantUnspecified && netIP.IsUnspecified():
617
+					matched = true
618
+				case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr):
619
+					matched = true
620
+				}
621
+			}
622
+		}
623
+		if matched {
624
+			matchedAddrs = append(matchedAddrs, ifAddr)
625
+		} else {
626
+			excludedAddrs = append(excludedAddrs, ifAddr)
627
+		}
628
+	}
629
+	return matchedAddrs, excludedAddrs, nil
630
+}
631
+
632
+// IfByNetwork returns an IfAddrs that are equal to or included within the
633
+// network passed in by selector.
634
+func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, error) {
635
+	var includedIfs, excludedIfs IfAddrs
636
+	for _, netStr := range strings.Split(selectorParam, "|") {
637
+		netAddr, err := NewIPAddr(netStr)
638
+		if err != nil {
639
+			return nil, nil, fmt.Errorf("unable to create an IP address from %+q: %v", netStr, err)
640
+		}
641
+
642
+		for _, ifAddr := range inputIfAddrs {
643
+			if netAddr.Contains(ifAddr.SockAddr) {
644
+				includedIfs = append(includedIfs, ifAddr)
645
+			} else {
646
+				excludedIfs = append(excludedIfs, ifAddr)
647
+			}
648
+		}
649
+	}
650
+
651
+	return includedIfs, excludedIfs, nil
652
+}
653
+
654
+// IncludeIfs returns an IfAddrs based on the passed in selector.
655
+func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
656
+	var includedIfs IfAddrs
657
+	var err error
658
+
659
+	switch strings.ToLower(selectorName) {
660
+	case "address":
661
+		includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs)
662
+	case "flag", "flags":
663
+		includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs)
664
+	case "name":
665
+		includedIfs, _, err = IfByName(selectorParam, inputIfAddrs)
666
+	case "network":
667
+		includedIfs, _, err = IfByNetwork(selectorParam, inputIfAddrs)
668
+	case "port":
669
+		includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs)
670
+	case "rfc", "rfcs":
671
+		includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs)
672
+	case "size":
673
+		includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs)
674
+	case "type":
675
+		includedIfs, _, err = IfByType(selectorParam, inputIfAddrs)
676
+	default:
677
+		return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName)
678
+	}
679
+
680
+	if err != nil {
681
+		return IfAddrs{}, err
682
+	}
683
+
684
+	return includedIfs, nil
685
+}
686
+
687
+// ExcludeIfs returns an IfAddrs based on the passed in selector.
688
+func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
689
+	var excludedIfs IfAddrs
690
+	var err error
691
+
692
+	switch strings.ToLower(selectorName) {
693
+	case "address":
694
+		_, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs)
695
+	case "flag", "flags":
696
+		_, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs)
697
+	case "name":
698
+		_, excludedIfs, err = IfByName(selectorParam, inputIfAddrs)
699
+	case "network":
700
+		_, excludedIfs, err = IfByNetwork(selectorParam, inputIfAddrs)
701
+	case "port":
702
+		_, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs)
703
+	case "rfc", "rfcs":
704
+		_, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs)
705
+	case "size":
706
+		_, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs)
707
+	case "type":
708
+		_, excludedIfs, err = IfByType(selectorParam, inputIfAddrs)
709
+	default:
710
+		return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName)
711
+	}
712
+
713
+	if err != nil {
714
+		return IfAddrs{}, err
715
+	}
716
+
717
+	return excludedIfs, nil
718
+}
719
+
720
+// SortIfBy returns an IfAddrs sorted based on the passed in selector.  Multiple
721
+// sort clauses can be passed in as a comma delimited list without whitespace.
722
+func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
723
+	sortedIfs := append(IfAddrs(nil), inputIfAddrs...)
724
+
725
+	clauses := strings.Split(selectorParam, ",")
726
+	sortFuncs := make([]CmpIfAddrFunc, len(clauses))
727
+
728
+	for i, clause := range clauses {
729
+		switch strings.TrimSpace(strings.ToLower(clause)) {
730
+		case "+address", "address":
731
+			// The "address" selector returns an array of IfAddrs
732
+			// ordered by the network address.  IfAddrs that are not
733
+			// comparable will be at the end of the list and in a
734
+			// non-deterministic order.
735
+			sortFuncs[i] = AscIfAddress
736
+		case "-address":
737
+			sortFuncs[i] = DescIfAddress
738
+		case "+name", "name":
739
+			// The "name" selector returns an array of IfAddrs
740
+			// ordered by the interface name.
741
+			sortFuncs[i] = AscIfName
742
+		case "-name":
743
+			sortFuncs[i] = DescIfName
744
+		case "+port", "port":
745
+			// The "port" selector returns an array of IfAddrs
746
+			// ordered by the port, if included in the IfAddr.
747
+			// IfAddrs that are not comparable will be at the end of
748
+			// the list and in a non-deterministic order.
749
+			sortFuncs[i] = AscIfPort
750
+		case "-port":
751
+			sortFuncs[i] = DescIfPort
752
+		case "+private", "private":
753
+			// The "private" selector returns an array of IfAddrs
754
+			// ordered by private addresses first.  IfAddrs that are
755
+			// not comparable will be at the end of the list and in
756
+			// a non-deterministic order.
757
+			sortFuncs[i] = AscIfPrivate
758
+		case "-private":
759
+			sortFuncs[i] = DescIfPrivate
760
+		case "+size", "size":
761
+			// The "size" selector returns an array of IfAddrs
762
+			// ordered by the size of the network mask, smaller mask
763
+			// (larger number of hosts per network) to largest
764
+			// (e.g. a /24 sorts before a /32).
765
+			sortFuncs[i] = AscIfNetworkSize
766
+		case "-size":
767
+			sortFuncs[i] = DescIfNetworkSize
768
+		case "+type", "type":
769
+			// The "type" selector returns an array of IfAddrs
770
+			// ordered by the type of the IfAddr.  The sort order is
771
+			// Unix, IPv4, then IPv6.
772
+			sortFuncs[i] = AscIfType
773
+		case "-type":
774
+			sortFuncs[i] = DescIfType
775
+		default:
776
+			// Return an empty list for invalid sort types.
777
+			return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause)
778
+		}
779
+	}
780
+
781
+	OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs)
782
+
783
+	return sortedIfs, nil
784
+}
785
+
786
+// UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching
787
+// selector.  UniqueIfAddrsBy assumes the input has already been sorted.
788
+func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) {
789
+	attrName := strings.ToLower(selectorName)
790
+
791
+	ifs := make(IfAddrs, 0, len(inputIfAddrs))
792
+	var lastMatch string
793
+	for _, ifAddr := range inputIfAddrs {
794
+		var out string
795
+		switch attrName {
796
+		case "address":
797
+			out = ifAddr.SockAddr.String()
798
+		case "name":
799
+			out = ifAddr.Name
800
+		default:
801
+			return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName)
802
+		}
803
+
804
+		switch {
805
+		case lastMatch == "", lastMatch != out:
806
+			lastMatch = out
807
+			ifs = append(ifs, ifAddr)
808
+		case lastMatch == out:
809
+			continue
810
+		}
811
+	}
812
+
813
+	return ifs, nil
814
+}
815
+
816
+// JoinIfAddrs joins an IfAddrs and returns a string
817
+func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) {
818
+	outputs := make([]string, 0, len(inputIfAddrs))
819
+	attrName := AttrName(strings.ToLower(selectorName))
820
+
821
+	for _, ifAddr := range inputIfAddrs {
822
+		var attrVal string
823
+		var err error
824
+		attrVal, err = ifAddr.Attr(attrName)
825
+		if err != nil {
826
+			return "", err
827
+		}
828
+		outputs = append(outputs, attrVal)
829
+	}
830
+	return strings.Join(outputs, joinStr), nil
831
+}
832
+
833
+// LimitIfAddrs returns a slice of IfAddrs based on the specified limit.
834
+func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) {
835
+	// Clamp the limit to the length of the array
836
+	if int(lim) > len(in) {
837
+		lim = uint(len(in))
838
+	}
839
+
840
+	return in[0:lim], nil
841
+}
842
+
843
+// OffsetIfAddrs returns a slice of IfAddrs based on the specified offset.
844
+func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) {
845
+	var end bool
846
+	if off < 0 {
847
+		end = true
848
+		off = off * -1
849
+	}
850
+
851
+	if off > len(in) {
852
+		return IfAddrs{}, fmt.Errorf("unable to seek past the end of the interface array: offset (%d) exceeds the number of interfaces (%d)", off, len(in))
853
+	}
854
+
855
+	if end {
856
+		return in[len(in)-off:], nil
857
+	}
858
+	return in[off:], nil
859
+}
860
+
861
+func (ifAddr IfAddr) String() string {
862
+	return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface)
863
+}
864
+
865
+// parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs
866
+// and Solaris.
867
+func parseDefaultIfNameFromRoute(routeOut string) (string, error) {
868
+	lines := strings.Split(routeOut, "\n")
869
+	for _, line := range lines {
870
+		kvs := strings.SplitN(line, ":", 2)
871
+		if len(kvs) != 2 {
872
+			continue
873
+		}
874
+
875
+		if strings.TrimSpace(kvs[0]) == "interface" {
876
+			ifName := strings.TrimSpace(kvs[1])
877
+			return ifName, nil
878
+		}
879
+	}
880
+
881
+	return "", errors.New("No default interface found")
882
+}
883
+
884
+// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for
885
+// Linux.
886
+func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
887
+	lines := strings.Split(routeOut, "\n")
888
+	re := regexp.MustCompile(`[\s]+`)
889
+	for _, line := range lines {
890
+		kvs := re.Split(line, -1)
891
+		if len(kvs) < 5 {
892
+			continue
893
+		}
894
+
895
+		if kvs[0] == "default" &&
896
+			kvs[1] == "via" &&
897
+			kvs[3] == "dev" {
898
+			ifName := strings.TrimSpace(kvs[4])
899
+			return ifName, nil
900
+		}
901
+	}
902
+
903
+	return "", errors.New("No default interface found")
904
+}
905
+
906
+// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and
907
+// `ipconfig` on Windows.
908
+func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) {
909
+	defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut)
910
+	if err != nil {
911
+		return "", err
912
+	}
913
+
914
+	ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut)
915
+	if err != nil {
916
+		return "", err
917
+	}
918
+
919
+	return ifName, nil
920
+}
921
+
922
+// parseDefaultIPAddrWindowsRoute parses the IP address on the default interface
923
+// `netstat -rn`.
924
+//
925
+// NOTES(sean): Only IPv4 addresses are parsed at this time.  If you have an
926
+// IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with
927
+// the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6
928
+// support added.
929
+func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
930
+	lines := strings.Split(routeOut, "\n")
931
+	re := regexp.MustCompile(`[\s]+`)
932
+	for _, line := range lines {
933
+		kvs := re.Split(strings.TrimSpace(line), -1)
934
+		if len(kvs) < 3 {
935
+			continue
936
+		}
937
+
938
+		if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" {
939
+			defaultIPAddr := strings.TrimSpace(kvs[3])
940
+			return defaultIPAddr, nil
941
+		}
942
+	}
943
+
944
+	return "", errors.New("No IP on default interface found")
945
+}
946
+
947
+// parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the
948
+// interface name forwarding traffic to the default gateway.
949
+func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) {
950
+	lines := strings.Split(routeOut, "\n")
951
+	ifNameRE := regexp.MustCompile(`^Ethernet adapter ([^\s:]+):`)
952
+	ipAddrRE := regexp.MustCompile(`^   IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`)
953
+	var ifName string
954
+	for _, line := range lines {
955
+		switch ifNameMatches := ifNameRE.FindStringSubmatch(line); {
956
+		case len(ifNameMatches) > 1:
957
+			ifName = ifNameMatches[1]
958
+			continue
959
+		}
960
+
961
+		switch ipAddrMatches := ipAddrRE.FindStringSubmatch(line); {
962
+		case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr:
963
+			return ifName, nil
964
+		}
965
+	}
966
+
967
+	return "", errors.New("No default interface found with matching IP")
968
+}
0 969
new file mode 100644
... ...
@@ -0,0 +1,65 @@
0
+package sockaddr
1
+
2
+import (
3
+	"fmt"
4
+	"net"
5
+)
6
+
7
+// IfAddr is a union of a SockAddr and a net.Interface.
8
+type IfAddr struct {
9
+	SockAddr
10
+	net.Interface
11
+}
12
+
13
+// Attr returns the named attribute as a string
14
+func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) {
15
+	val := IfAddrAttr(ifAddr, attrName)
16
+	if val != "" {
17
+		return val, nil
18
+	}
19
+
20
+	return Attr(ifAddr.SockAddr, attrName)
21
+}
22
+
23
+// Attr returns the named attribute as a string
24
+func Attr(sa SockAddr, attrName AttrName) (string, error) {
25
+	switch sockType := sa.Type(); {
26
+	case sockType&TypeIP != 0:
27
+		ip := *ToIPAddr(sa)
28
+		attrVal := IPAddrAttr(ip, attrName)
29
+		if attrVal != "" {
30
+			return attrVal, nil
31
+		}
32
+
33
+		if sockType == TypeIPv4 {
34
+			ipv4 := *ToIPv4Addr(sa)
35
+			attrVal := IPv4AddrAttr(ipv4, attrName)
36
+			if attrVal != "" {
37
+				return attrVal, nil
38
+			}
39
+		} else if sockType == TypeIPv6 {
40
+			ipv6 := *ToIPv6Addr(sa)
41
+			attrVal := IPv6AddrAttr(ipv6, attrName)
42
+			if attrVal != "" {
43
+				return attrVal, nil
44
+			}
45
+		}
46
+
47
+	case sockType == TypeUnix:
48
+		us := *ToUnixSock(sa)
49
+		attrVal := UnixSockAttr(us, attrName)
50
+		if attrVal != "" {
51
+			return attrVal, nil
52
+		}
53
+	}
54
+
55
+	// Non type-specific attributes
56
+	switch attrName {
57
+	case "string":
58
+		return sa.String(), nil
59
+	case "type":
60
+		return sa.Type().String(), nil
61
+	}
62
+
63
+	return "", fmt.Errorf("unsupported attribute name %q", attrName)
64
+}
0 65
new file mode 100644
... ...
@@ -0,0 +1,169 @@
0
+package sockaddr
1
+
2
+import (
3
+	"fmt"
4
+	"math/big"
5
+	"net"
6
+	"strings"
7
+)
8
+
9
+// Constants for the sizes of IPv3, IPv4, and IPv6 address types.
10
+const (
11
+	IPv3len = 6
12
+	IPv4len = 4
13
+	IPv6len = 16
14
+)
15
+
16
+// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses,
17
+// networks, and socket endpoints.
18
+type IPAddr interface {
19
+	SockAddr
20
+	AddressBinString() string
21
+	AddressHexString() string
22
+	Cmp(SockAddr) int
23
+	CmpAddress(SockAddr) int
24
+	CmpPort(SockAddr) int
25
+	FirstUsable() IPAddr
26
+	Host() IPAddr
27
+	IPPort() IPPort
28
+	LastUsable() IPAddr
29
+	Maskbits() int
30
+	NetIP() *net.IP
31
+	NetIPMask() *net.IPMask
32
+	NetIPNet() *net.IPNet
33
+	Network() IPAddr
34
+	Octets() []int
35
+}
36
+
37
+// IPPort is the type for an IP port number for the TCP and UDP IP transports.
38
+type IPPort uint16
39
+
40
+// IPPrefixLen is a typed integer representing the prefix length for a given
41
+// IPAddr.
42
+type IPPrefixLen byte
43
+
44
+// ipAddrAttrMap is a map of the IPAddr type-specific attributes.
45
+var ipAddrAttrMap map[AttrName]func(IPAddr) string
46
+var ipAddrAttrs []AttrName
47
+
48
+func init() {
49
+	ipAddrInit()
50
+}
51
+
52
+// NewIPAddr creates a new IPAddr from a string.  Returns nil if the string is
53
+// not an IPv4 or an IPv6 address.
54
+func NewIPAddr(addr string) (IPAddr, error) {
55
+	ipv4Addr, err := NewIPv4Addr(addr)
56
+	if err == nil {
57
+		return ipv4Addr, nil
58
+	}
59
+
60
+	ipv6Addr, err := NewIPv6Addr(addr)
61
+	if err == nil {
62
+		return ipv6Addr, nil
63
+	}
64
+
65
+	return nil, fmt.Errorf("invalid IPAddr %v", addr)
66
+}
67
+
68
+// IPAddrAttr returns a string representation of an attribute for the given
69
+// IPAddr.
70
+func IPAddrAttr(ip IPAddr, selector AttrName) string {
71
+	fn, found := ipAddrAttrMap[selector]
72
+	if !found {
73
+		return ""
74
+	}
75
+
76
+	return fn(ip)
77
+}
78
+
79
+// IPAttrs returns a list of attributes supported by the IPAddr type
80
+func IPAttrs() []AttrName {
81
+	return ipAddrAttrs
82
+}
83
+
84
+// MustIPAddr is a helper method that must return an IPAddr or panic on invalid
85
+// input.
86
+func MustIPAddr(addr string) IPAddr {
87
+	ip, err := NewIPAddr(addr)
88
+	if err != nil {
89
+		panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err))
90
+	}
91
+	return ip
92
+}
93
+
94
+// ipAddrInit is called once at init()
95
+func ipAddrInit() {
96
+	// Sorted for human readability
97
+	ipAddrAttrs = []AttrName{
98
+		"host",
99
+		"address",
100
+		"port",
101
+		"netmask",
102
+		"network",
103
+		"mask_bits",
104
+		"binary",
105
+		"hex",
106
+		"first_usable",
107
+		"last_usable",
108
+		"octets",
109
+	}
110
+
111
+	ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{
112
+		"address": func(ip IPAddr) string {
113
+			return ip.NetIP().String()
114
+		},
115
+		"binary": func(ip IPAddr) string {
116
+			return ip.AddressBinString()
117
+		},
118
+		"first_usable": func(ip IPAddr) string {
119
+			return ip.FirstUsable().String()
120
+		},
121
+		"hex": func(ip IPAddr) string {
122
+			return ip.AddressHexString()
123
+		},
124
+		"host": func(ip IPAddr) string {
125
+			return ip.Host().String()
126
+		},
127
+		"last_usable": func(ip IPAddr) string {
128
+			return ip.LastUsable().String()
129
+		},
130
+		"mask_bits": func(ip IPAddr) string {
131
+			return fmt.Sprintf("%d", ip.Maskbits())
132
+		},
133
+		"netmask": func(ip IPAddr) string {
134
+			switch v := ip.(type) {
135
+			case IPv4Addr:
136
+				ipv4Mask := IPv4Addr{
137
+					Address: IPv4Address(v.Mask),
138
+					Mask:    IPv4HostMask,
139
+				}
140
+				return ipv4Mask.String()
141
+			case IPv6Addr:
142
+				ipv6Mask := new(big.Int)
143
+				ipv6Mask.Set(v.Mask)
144
+				ipv6MaskAddr := IPv6Addr{
145
+					Address: IPv6Address(ipv6Mask),
146
+					Mask:    ipv6HostMask,
147
+				}
148
+				return ipv6MaskAddr.String()
149
+			default:
150
+				return fmt.Sprintf("<unsupported type: %T>", ip)
151
+			}
152
+		},
153
+		"network": func(ip IPAddr) string {
154
+			return ip.Network().NetIP().String()
155
+		},
156
+		"octets": func(ip IPAddr) string {
157
+			octets := ip.Octets()
158
+			octetStrs := make([]string, 0, len(octets))
159
+			for _, octet := range octets {
160
+				octetStrs = append(octetStrs, fmt.Sprintf("%d", octet))
161
+			}
162
+			return strings.Join(octetStrs, " ")
163
+		},
164
+		"port": func(ip IPAddr) string {
165
+			return fmt.Sprintf("%d", ip.IPPort())
166
+		},
167
+	}
168
+}
0 169
new file mode 100644
... ...
@@ -0,0 +1,98 @@
0
+package sockaddr
1
+
2
+import "bytes"
3
+
4
+type IPAddrs []IPAddr
5
+
6
+func (s IPAddrs) Len() int      { return len(s) }
7
+func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
8
+
9
+// // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used
10
+// // by the routines in this package.  The SortIPAddrsByCmp type is used to
11
+// // sort IPAddrs by Cmp()
12
+// type SortIPAddrsByCmp struct{ IPAddrs }
13
+
14
+// // Less reports whether the element with index i should sort before the
15
+// // element with index j.
16
+// func (s SortIPAddrsByCmp) Less(i, j int) bool {
17
+// 	// Sort by Type, then address, then port number.
18
+// 	return Less(s.IPAddrs[i], s.IPAddrs[j])
19
+// }
20
+
21
+// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
22
+// can be used by the routines in this package.  The
23
+// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
24
+// network (most specific to largest network).
25
+type SortIPAddrsByNetworkSize struct{ IPAddrs }
26
+
27
+// Less reports whether the element with index i should sort before the
28
+// element with index j.
29
+func (s SortIPAddrsByNetworkSize) Less(i, j int) bool {
30
+	// Sort masks with a larger binary value (i.e. fewer hosts per network
31
+	// prefix) after masks with a smaller value (larger number of hosts per
32
+	// prefix).
33
+	switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) {
34
+	case 0:
35
+		// Fall through to the second test if the net.IPMasks are the
36
+		// same.
37
+		break
38
+	case 1:
39
+		return true
40
+	case -1:
41
+		return false
42
+	default:
43
+		panic("bad, m'kay?")
44
+	}
45
+
46
+	// Sort IPs based on the length (i.e. prefer IPv4 over IPv6).
47
+	iLen := len(*s.IPAddrs[i].NetIP())
48
+	jLen := len(*s.IPAddrs[j].NetIP())
49
+	if iLen != jLen {
50
+		return iLen > jLen
51
+	}
52
+
53
+	// Sort IPs based on their network address from lowest to highest.
54
+	switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) {
55
+	case 0:
56
+		break
57
+	case 1:
58
+		return false
59
+	case -1:
60
+		return true
61
+	default:
62
+		panic("lol wut?")
63
+	}
64
+
65
+	// If a host does not have a port set, it always sorts after hosts
66
+	// that have a port (e.g. a host with a /32 and port number is more
67
+	// specific and should sort first over a host with a /32 but no port
68
+	// set).
69
+	if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 {
70
+		return false
71
+	}
72
+	return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort()
73
+}
74
+
75
+// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
76
+// can be used by the routines in this package.  The
77
+// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
78
+// network (most specific to largest network).
79
+type SortIPAddrsBySpecificMaskLen struct{ IPAddrs }
80
+
81
+// Less reports whether the element with index i should sort before the
82
+// element with index j.
83
+func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool {
84
+	return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits()
85
+}
86
+
87
+// SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can
88
+// be used by the routines in this package.  The SortIPAddrsByBroadMaskLen
89
+// type is used to sort IPAddrs by largest network (i.e. largest subnets
90
+// first).
91
+type SortIPAddrsByBroadMaskLen struct{ IPAddrs }
92
+
93
+// Less reports whether the element with index i should sort before the
94
+// element with index j.
95
+func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool {
96
+	return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits()
97
+}
0 98
new file mode 100644
... ...
@@ -0,0 +1,515 @@
0
+package sockaddr
1
+
2
+import (
3
+	"encoding/binary"
4
+	"fmt"
5
+	"net"
6
+	"regexp"
7
+	"strconv"
8
+	"strings"
9
+)
10
+
11
+type (
12
+	// IPv4Address is a named type representing an IPv4 address.
13
+	IPv4Address uint32
14
+
15
+	// IPv4Network is a named type representing an IPv4 network.
16
+	IPv4Network uint32
17
+
18
+	// IPv4Mask is a named type representing an IPv4 network mask.
19
+	IPv4Mask uint32
20
+)
21
+
22
+// IPv4HostMask is a constant represents a /32 IPv4 Address
23
+// (i.e. 255.255.255.255).
24
+const IPv4HostMask = IPv4Mask(0xffffffff)
25
+
26
+// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes.
27
+var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string
28
+var ipv4AddrAttrs []AttrName
29
+var trailingHexNetmaskRE *regexp.Regexp
30
+
31
+// IPv4Addr implements a convenience wrapper around the union of Go's
32
+// built-in net.IP and net.IPNet types.  In UNIX-speak, IPv4Addr implements
33
+// `sockaddr` when the the address family is set to AF_INET
34
+// (i.e. `sockaddr_in`).
35
+type IPv4Addr struct {
36
+	IPAddr
37
+	Address IPv4Address
38
+	Mask    IPv4Mask
39
+	Port    IPPort
40
+}
41
+
42
+func init() {
43
+	ipv4AddrInit()
44
+	trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`)
45
+}
46
+
47
+// NewIPv4Addr creates an IPv4Addr from a string.  String can be in the form
48
+// of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is
49
+// assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32`
50
+// mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port
51
+// initialized to zero).  ipv4Str can not be a hostname.
52
+//
53
+// NOTE: Many net.*() routines will initialize and return an IPv6 address.
54
+// To create uint32 values from net.IP, always test to make sure the address
55
+// returned can be converted to a 4 byte array using To4().
56
+func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) {
57
+	// Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go.  In
58
+	// particular, clients with the Barracuda VPN client will see something like:
59
+	// `192.168.3.51/00ffffff` as their IP address.
60
+	if match := trailingHexNetmaskRE.FindStringIndex(ipv4Str); match != nil {
61
+		ipv4Str = ipv4Str[:match[0]]
62
+	}
63
+
64
+	// Parse as an IPv4 CIDR
65
+	ipAddr, network, err := net.ParseCIDR(ipv4Str)
66
+	if err == nil {
67
+		ipv4 := ipAddr.To4()
68
+		if ipv4 == nil {
69
+			return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str)
70
+		}
71
+
72
+		// If we see an IPv6 netmask, convert it to an IPv4 mask.
73
+		netmaskSepPos := strings.LastIndexByte(ipv4Str, '/')
74
+		if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) {
75
+			netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8)
76
+			if err != nil {
77
+				return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err)
78
+			} else if netMask > 128 {
79
+				return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str)
80
+			}
81
+
82
+			if netMask >= 96 {
83
+				// Convert the IPv6 netmask to an IPv4 netmask
84
+				network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8)
85
+			}
86
+		}
87
+		ipv4Addr := IPv4Addr{
88
+			Address: IPv4Address(binary.BigEndian.Uint32(ipv4)),
89
+			Mask:    IPv4Mask(binary.BigEndian.Uint32(network.Mask)),
90
+		}
91
+		return ipv4Addr, nil
92
+	}
93
+
94
+	// Attempt to parse ipv4Str as a /32 host with a port number.
95
+	tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str)
96
+	if err == nil {
97
+		ipv4 := tcpAddr.IP.To4()
98
+		if ipv4 == nil {
99
+			return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str)
100
+		}
101
+
102
+		ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
103
+		ipv4Addr := IPv4Addr{
104
+			Address: IPv4Address(ipv4Uint32),
105
+			Mask:    IPv4HostMask,
106
+			Port:    IPPort(tcpAddr.Port),
107
+		}
108
+
109
+		return ipv4Addr, nil
110
+	}
111
+
112
+	// Parse as a naked IPv4 address
113
+	ip := net.ParseIP(ipv4Str)
114
+	if ip != nil {
115
+		ipv4 := ip.To4()
116
+		if ipv4 == nil {
117
+			return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str)
118
+		}
119
+
120
+		ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
121
+		ipv4Addr := IPv4Addr{
122
+			Address: IPv4Address(ipv4Uint32),
123
+			Mask:    IPv4HostMask,
124
+		}
125
+		return ipv4Addr, nil
126
+	}
127
+
128
+	return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err)
129
+}
130
+
131
+// AddressBinString returns a string with the IPv4Addr's Address represented
132
+// as a sequence of '0' and '1' characters.  This method is useful for
133
+// debugging or by operators who want to inspect an address.
134
+func (ipv4 IPv4Addr) AddressBinString() string {
135
+	return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2))
136
+}
137
+
138
+// AddressHexString returns a string with the IPv4Addr address represented as
139
+// a sequence of hex characters.  This method is useful for debugging or by
140
+// operators who want to inspect an address.
141
+func (ipv4 IPv4Addr) AddressHexString() string {
142
+	return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16))
143
+}
144
+
145
+// Broadcast is an IPv4Addr-only method that returns the broadcast address of
146
+// the network.
147
+//
148
+// NOTE: IPv6 only supports multicast, so this method only exists for
149
+// IPv4Addr.
150
+func (ipv4 IPv4Addr) Broadcast() IPAddr {
151
+	// Nothing should listen on a broadcast address.
152
+	return IPv4Addr{
153
+		Address: IPv4Address(ipv4.BroadcastAddress()),
154
+		Mask:    IPv4HostMask,
155
+	}
156
+}
157
+
158
+// BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast
159
+// address.
160
+func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network {
161
+	return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask))
162
+}
163
+
164
+// CmpAddress follows the Cmp() standard protocol and returns:
165
+//
166
+// - -1 If the receiver should sort first because its address is lower than arg
167
+// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is
168
+//   of a different type.
169
+// - 1 If the argument should sort first.
170
+func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int {
171
+	ipv4b, ok := sa.(IPv4Addr)
172
+	if !ok {
173
+		return sortDeferDecision
174
+	}
175
+
176
+	switch {
177
+	case ipv4.Address == ipv4b.Address:
178
+		return sortDeferDecision
179
+	case ipv4.Address < ipv4b.Address:
180
+		return sortReceiverBeforeArg
181
+	default:
182
+		return sortArgBeforeReceiver
183
+	}
184
+}
185
+
186
+// CmpPort follows the Cmp() standard protocol and returns:
187
+//
188
+// - -1 If the receiver should sort first because its port is lower than arg
189
+// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr,
190
+//   regardless of type.
191
+// - 1 If the argument should sort first.
192
+func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int {
193
+	var saPort IPPort
194
+	switch v := sa.(type) {
195
+	case IPv4Addr:
196
+		saPort = v.Port
197
+	case IPv6Addr:
198
+		saPort = v.Port
199
+	default:
200
+		return sortDeferDecision
201
+	}
202
+
203
+	switch {
204
+	case ipv4.Port == saPort:
205
+		return sortDeferDecision
206
+	case ipv4.Port < saPort:
207
+		return sortReceiverBeforeArg
208
+	default:
209
+		return sortArgBeforeReceiver
210
+	}
211
+}
212
+
213
+// CmpRFC follows the Cmp() standard protocol and returns:
214
+//
215
+// - -1 If the receiver should sort first because it belongs to the RFC and its
216
+//   arg does not
217
+// - 0 if the receiver and arg both belong to the same RFC or neither do.
218
+// - 1 If the arg belongs to the RFC but receiver does not.
219
+func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
220
+	recvInRFC := IsRFC(rfcNum, ipv4)
221
+	ipv4b, ok := sa.(IPv4Addr)
222
+	if !ok {
223
+		// If the receiver is part of the desired RFC and the SockAddr
224
+		// argument is not, return -1 so that the receiver sorts before
225
+		// the non-IPv4 SockAddr.  Conversely, if the receiver is not
226
+		// part of the RFC, punt on sorting and leave it for the next
227
+		// sorter.
228
+		if recvInRFC {
229
+			return sortReceiverBeforeArg
230
+		} else {
231
+			return sortDeferDecision
232
+		}
233
+	}
234
+
235
+	argInRFC := IsRFC(rfcNum, ipv4b)
236
+	switch {
237
+	case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
238
+		// If a and b both belong to the RFC, or neither belong to
239
+		// rfcNum, defer sorting to the next sorter.
240
+		return sortDeferDecision
241
+	case recvInRFC && !argInRFC:
242
+		return sortReceiverBeforeArg
243
+	default:
244
+		return sortArgBeforeReceiver
245
+	}
246
+}
247
+
248
+// Contains returns true if the SockAddr is contained within the receiver.
249
+func (ipv4 IPv4Addr) Contains(sa SockAddr) bool {
250
+	ipv4b, ok := sa.(IPv4Addr)
251
+	if !ok {
252
+		return false
253
+	}
254
+
255
+	return ipv4.ContainsNetwork(ipv4b)
256
+}
257
+
258
+// ContainsAddress returns true if the IPv4Address is contained within the
259
+// receiver.
260
+func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool {
261
+	return IPv4Address(ipv4.NetworkAddress()) <= x &&
262
+		IPv4Address(ipv4.BroadcastAddress()) >= x
263
+}
264
+
265
+// ContainsNetwork returns true if the network from IPv4Addr is contained
266
+// within the receiver.
267
+func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool {
268
+	return ipv4.NetworkAddress() <= x.NetworkAddress() &&
269
+		ipv4.BroadcastAddress() >= x.BroadcastAddress()
270
+}
271
+
272
+// DialPacketArgs returns the arguments required to be passed to
273
+// net.DialUDP().  If the Mask of ipv4 is not a /32 or the Port is 0,
274
+// DialPacketArgs() will fail.  See Host() to create an IPv4Addr with its
275
+// mask set to /32.
276
+func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) {
277
+	if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
278
+		return "udp4", ""
279
+	}
280
+	return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
281
+}
282
+
283
+// DialStreamArgs returns the arguments required to be passed to
284
+// net.DialTCP().  If the Mask of ipv4 is not a /32 or the Port is 0,
285
+// DialStreamArgs() will fail.  See Host() to create an IPv4Addr with its
286
+// mask set to /32.
287
+func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) {
288
+	if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
289
+		return "tcp4", ""
290
+	}
291
+	return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
292
+}
293
+
294
+// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
295
+func (ipv4 IPv4Addr) Equal(sa SockAddr) bool {
296
+	ipv4b, ok := sa.(IPv4Addr)
297
+	if !ok {
298
+		return false
299
+	}
300
+
301
+	if ipv4.Port != ipv4b.Port {
302
+		return false
303
+	}
304
+
305
+	if ipv4.Address != ipv4b.Address {
306
+		return false
307
+	}
308
+
309
+	if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() {
310
+		return false
311
+	}
312
+
313
+	return true
314
+}
315
+
316
+// FirstUsable returns an IPv4Addr set to the first address following the
317
+// network prefix.  The first usable address in a network is normally the
318
+// gateway and should not be used except by devices forwarding packets
319
+// between two administratively distinct networks (i.e. a router).  This
320
+// function does not discriminate against first usable vs "first address that
321
+// should be used."  For example, FirstUsable() on "192.168.1.10/24" would
322
+// return the address "192.168.1.1/24".
323
+func (ipv4 IPv4Addr) FirstUsable() IPAddr {
324
+	addr := ipv4.NetworkAddress()
325
+
326
+	// If /32, return the address itself. If /31 assume a point-to-point
327
+	// link and return the lower address.
328
+	if ipv4.Maskbits() < 31 {
329
+		addr++
330
+	}
331
+
332
+	return IPv4Addr{
333
+		Address: IPv4Address(addr),
334
+		Mask:    IPv4HostMask,
335
+	}
336
+}
337
+
338
+// Host returns a copy of ipv4 with its mask set to /32 so that it can be
339
+// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
340
+// ListenStreamArgs().
341
+func (ipv4 IPv4Addr) Host() IPAddr {
342
+	// Nothing should listen on a broadcast address.
343
+	return IPv4Addr{
344
+		Address: ipv4.Address,
345
+		Mask:    IPv4HostMask,
346
+		Port:    ipv4.Port,
347
+	}
348
+}
349
+
350
+// IPPort returns the Port number attached to the IPv4Addr
351
+func (ipv4 IPv4Addr) IPPort() IPPort {
352
+	return ipv4.Port
353
+}
354
+
355
+// LastUsable returns the last address before the broadcast address in a
356
+// given network.
357
+func (ipv4 IPv4Addr) LastUsable() IPAddr {
358
+	addr := ipv4.BroadcastAddress()
359
+
360
+	// If /32, return the address itself. If /31 assume a point-to-point
361
+	// link and return the upper address.
362
+	if ipv4.Maskbits() < 31 {
363
+		addr--
364
+	}
365
+
366
+	return IPv4Addr{
367
+		Address: IPv4Address(addr),
368
+		Mask:    IPv4HostMask,
369
+	}
370
+}
371
+
372
+// ListenPacketArgs returns the arguments required to be passed to
373
+// net.ListenUDP().  If the Mask of ipv4 is not a /32, ListenPacketArgs()
374
+// will fail.  See Host() to create an IPv4Addr with its mask set to /32.
375
+func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) {
376
+	if ipv4.Mask != IPv4HostMask {
377
+		return "udp4", ""
378
+	}
379
+	return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
380
+}
381
+
382
+// ListenStreamArgs returns the arguments required to be passed to
383
+// net.ListenTCP().  If the Mask of ipv4 is not a /32, ListenStreamArgs()
384
+// will fail.  See Host() to create an IPv4Addr with its mask set to /32.
385
+func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) {
386
+	if ipv4.Mask != IPv4HostMask {
387
+		return "tcp4", ""
388
+	}
389
+	return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
390
+}
391
+
392
+// Maskbits returns the number of network mask bits in a given IPv4Addr.  For
393
+// example, the Maskbits() of "192.168.1.1/24" would return 24.
394
+func (ipv4 IPv4Addr) Maskbits() int {
395
+	mask := make(net.IPMask, IPv4len)
396
+	binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask))
397
+	maskOnes, _ := mask.Size()
398
+	return maskOnes
399
+}
400
+
401
+// MustIPv4Addr is a helper method that must return an IPv4Addr or panic on
402
+// invalid input.
403
+func MustIPv4Addr(addr string) IPv4Addr {
404
+	ipv4, err := NewIPv4Addr(addr)
405
+	if err != nil {
406
+		panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err))
407
+	}
408
+	return ipv4
409
+}
410
+
411
+// NetIP returns the address as a net.IP (address is always presized to
412
+// IPv4).
413
+func (ipv4 IPv4Addr) NetIP() *net.IP {
414
+	x := make(net.IP, IPv4len)
415
+	binary.BigEndian.PutUint32(x, uint32(ipv4.Address))
416
+	return &x
417
+}
418
+
419
+// NetIPMask create a new net.IPMask from the IPv4Addr.
420
+func (ipv4 IPv4Addr) NetIPMask() *net.IPMask {
421
+	ipv4Mask := net.IPMask{}
422
+	ipv4Mask = make(net.IPMask, IPv4len)
423
+	binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask))
424
+	return &ipv4Mask
425
+}
426
+
427
+// NetIPNet create a new net.IPNet from the IPv4Addr.
428
+func (ipv4 IPv4Addr) NetIPNet() *net.IPNet {
429
+	ipv4net := &net.IPNet{}
430
+	ipv4net.IP = make(net.IP, IPv4len)
431
+	binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress()))
432
+	ipv4net.Mask = *ipv4.NetIPMask()
433
+	return ipv4net
434
+}
435
+
436
+// Network returns the network prefix or network address for a given network.
437
+func (ipv4 IPv4Addr) Network() IPAddr {
438
+	return IPv4Addr{
439
+		Address: IPv4Address(ipv4.NetworkAddress()),
440
+		Mask:    ipv4.Mask,
441
+	}
442
+}
443
+
444
+// NetworkAddress returns an IPv4Network of the IPv4Addr's network address.
445
+func (ipv4 IPv4Addr) NetworkAddress() IPv4Network {
446
+	return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask))
447
+}
448
+
449
+// Octets returns a slice of the four octets in an IPv4Addr's Address.  The
450
+// order of the bytes is big endian.
451
+func (ipv4 IPv4Addr) Octets() []int {
452
+	return []int{
453
+		int(ipv4.Address >> 24),
454
+		int((ipv4.Address >> 16) & 0xff),
455
+		int((ipv4.Address >> 8) & 0xff),
456
+		int(ipv4.Address & 0xff),
457
+	}
458
+}
459
+
460
+// String returns a string representation of the IPv4Addr
461
+func (ipv4 IPv4Addr) String() string {
462
+	if ipv4.Port != 0 {
463
+		return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
464
+	}
465
+
466
+	if ipv4.Maskbits() == 32 {
467
+		return ipv4.NetIP().String()
468
+	}
469
+
470
+	return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits())
471
+}
472
+
473
+// Type is used as a type switch and returns TypeIPv4
474
+func (IPv4Addr) Type() SockAddrType {
475
+	return TypeIPv4
476
+}
477
+
478
+// IPv4AddrAttr returns a string representation of an attribute for the given
479
+// IPv4Addr.
480
+func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string {
481
+	fn, found := ipv4AddrAttrMap[selector]
482
+	if !found {
483
+		return ""
484
+	}
485
+
486
+	return fn(ipv4)
487
+}
488
+
489
+// IPv4Attrs returns a list of attributes supported by the IPv4Addr type
490
+func IPv4Attrs() []AttrName {
491
+	return ipv4AddrAttrs
492
+}
493
+
494
+// ipv4AddrInit is called once at init()
495
+func ipv4AddrInit() {
496
+	// Sorted for human readability
497
+	ipv4AddrAttrs = []AttrName{
498
+		"size", // Same position as in IPv6 for output consistency
499
+		"broadcast",
500
+		"uint32",
501
+	}
502
+
503
+	ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{
504
+		"broadcast": func(ipv4 IPv4Addr) string {
505
+			return ipv4.Broadcast().String()
506
+		},
507
+		"size": func(ipv4 IPv4Addr) string {
508
+			return fmt.Sprintf("%d", 1<<uint(IPv4len*8-ipv4.Maskbits()))
509
+		},
510
+		"uint32": func(ipv4 IPv4Addr) string {
511
+			return fmt.Sprintf("%d", uint32(ipv4.Address))
512
+		},
513
+	}
514
+}
0 515
new file mode 100644
... ...
@@ -0,0 +1,591 @@
0
+package sockaddr
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/binary"
5
+	"fmt"
6
+	"math/big"
7
+	"net"
8
+)
9
+
10
+type (
11
+	// IPv6Address is a named type representing an IPv6 address.
12
+	IPv6Address *big.Int
13
+
14
+	// IPv6Network is a named type representing an IPv6 network.
15
+	IPv6Network *big.Int
16
+
17
+	// IPv6Mask is a named type representing an IPv6 network mask.
18
+	IPv6Mask *big.Int
19
+)
20
+
21
+// IPv6HostPrefix is a constant represents a /128 IPv6 Prefix.
22
+const IPv6HostPrefix = IPPrefixLen(128)
23
+
24
+// ipv6HostMask is an unexported big.Int representing a /128 IPv6 address.
25
+// This value must be a constant and always set to all ones.
26
+var ipv6HostMask IPv6Mask
27
+
28
+// ipv6AddrAttrMap is a map of the IPv6Addr type-specific attributes.
29
+var ipv6AddrAttrMap map[AttrName]func(IPv6Addr) string
30
+var ipv6AddrAttrs []AttrName
31
+
32
+func init() {
33
+	biMask := new(big.Int)
34
+	biMask.SetBytes([]byte{
35
+		0xff, 0xff,
36
+		0xff, 0xff,
37
+		0xff, 0xff,
38
+		0xff, 0xff,
39
+		0xff, 0xff,
40
+		0xff, 0xff,
41
+		0xff, 0xff,
42
+		0xff, 0xff,
43
+	},
44
+	)
45
+	ipv6HostMask = IPv6Mask(biMask)
46
+
47
+	ipv6AddrInit()
48
+}
49
+
50
+// IPv6Addr implements a convenience wrapper around the union of Go's
51
+// built-in net.IP and net.IPNet types.  In UNIX-speak, IPv6Addr implements
52
+// `sockaddr` when the the address family is set to AF_INET6
53
+// (i.e. `sockaddr_in6`).
54
+type IPv6Addr struct {
55
+	IPAddr
56
+	Address IPv6Address
57
+	Mask    IPv6Mask
58
+	Port    IPPort
59
+}
60
+
61
+// NewIPv6Addr creates an IPv6Addr from a string.  String can be in the form of
62
+// an an IPv6:port (e.g. `[2001:4860:0:2001::68]:80`, in which case the mask is
63
+// assumed to be a /128), an IPv6 address (e.g. `2001:4860:0:2001::68`, also
64
+// with a `/128` mask), an IPv6 CIDR (e.g. `2001:4860:0:2001::68/64`, which has
65
+// its IP port initialized to zero).  ipv6Str can not be a hostname.
66
+//
67
+// NOTE: Many net.*() routines will initialize and return an IPv4 address.
68
+// Always test to make sure the address returned cannot be converted to a 4 byte
69
+// array using To4().
70
+func NewIPv6Addr(ipv6Str string) (IPv6Addr, error) {
71
+	v6Addr := false
72
+LOOP:
73
+	for i := 0; i < len(ipv6Str); i++ {
74
+		switch ipv6Str[i] {
75
+		case '.':
76
+			break LOOP
77
+		case ':':
78
+			v6Addr = true
79
+			break LOOP
80
+		}
81
+	}
82
+
83
+	if !v6Addr {
84
+		return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv6 address, appears to be an IPv4 address", ipv6Str)
85
+	}
86
+
87
+	// Attempt to parse ipv6Str as a /128 host with a port number.
88
+	tcpAddr, err := net.ResolveTCPAddr("tcp6", ipv6Str)
89
+	if err == nil {
90
+		ipv6 := tcpAddr.IP.To16()
91
+		if ipv6 == nil {
92
+			return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as a 16byte IPv6 address", ipv6Str)
93
+		}
94
+
95
+		ipv6BigIntAddr := new(big.Int)
96
+		ipv6BigIntAddr.SetBytes(ipv6)
97
+
98
+		ipv6BigIntMask := new(big.Int)
99
+		ipv6BigIntMask.Set(ipv6HostMask)
100
+
101
+		ipv6Addr := IPv6Addr{
102
+			Address: IPv6Address(ipv6BigIntAddr),
103
+			Mask:    IPv6Mask(ipv6BigIntMask),
104
+			Port:    IPPort(tcpAddr.Port),
105
+		}
106
+
107
+		return ipv6Addr, nil
108
+	}
109
+
110
+	// Parse as a naked IPv6 address.  Trim square brackets if present.
111
+	if len(ipv6Str) > 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' {
112
+		ipv6Str = ipv6Str[1 : len(ipv6Str)-1]
113
+	}
114
+	ip := net.ParseIP(ipv6Str)
115
+	if ip != nil {
116
+		ipv6 := ip.To16()
117
+		if ipv6 == nil {
118
+			return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str)
119
+		}
120
+
121
+		ipv6BigIntAddr := new(big.Int)
122
+		ipv6BigIntAddr.SetBytes(ipv6)
123
+
124
+		ipv6BigIntMask := new(big.Int)
125
+		ipv6BigIntMask.Set(ipv6HostMask)
126
+
127
+		return IPv6Addr{
128
+			Address: IPv6Address(ipv6BigIntAddr),
129
+			Mask:    IPv6Mask(ipv6BigIntMask),
130
+		}, nil
131
+	}
132
+
133
+	// Parse as an IPv6 CIDR
134
+	ipAddr, network, err := net.ParseCIDR(ipv6Str)
135
+	if err == nil {
136
+		ipv6 := ipAddr.To16()
137
+		if ipv6 == nil {
138
+			return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str)
139
+		}
140
+
141
+		ipv6BigIntAddr := new(big.Int)
142
+		ipv6BigIntAddr.SetBytes(ipv6)
143
+
144
+		ipv6BigIntMask := new(big.Int)
145
+		ipv6BigIntMask.SetBytes(network.Mask)
146
+
147
+		ipv6Addr := IPv6Addr{
148
+			Address: IPv6Address(ipv6BigIntAddr),
149
+			Mask:    IPv6Mask(ipv6BigIntMask),
150
+		}
151
+		return ipv6Addr, nil
152
+	}
153
+
154
+	return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err)
155
+}
156
+
157
+// AddressBinString returns a string with the IPv6Addr's Address represented
158
+// as a sequence of '0' and '1' characters.  This method is useful for
159
+// debugging or by operators who want to inspect an address.
160
+func (ipv6 IPv6Addr) AddressBinString() string {
161
+	bi := big.Int(*ipv6.Address)
162
+	return fmt.Sprintf("%0128s", bi.Text(2))
163
+}
164
+
165
+// AddressHexString returns a string with the IPv6Addr address represented as
166
+// a sequence of hex characters.  This method is useful for debugging or by
167
+// operators who want to inspect an address.
168
+func (ipv6 IPv6Addr) AddressHexString() string {
169
+	bi := big.Int(*ipv6.Address)
170
+	return fmt.Sprintf("%032s", bi.Text(16))
171
+}
172
+
173
+// CmpAddress follows the Cmp() standard protocol and returns:
174
+//
175
+// - -1 If the receiver should sort first because its address is lower than arg
176
+// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a
177
+//   different type.
178
+// - 1 If the argument should sort first.
179
+func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int {
180
+	ipv6b, ok := sa.(IPv6Addr)
181
+	if !ok {
182
+		return sortDeferDecision
183
+	}
184
+
185
+	ipv6aBigInt := new(big.Int)
186
+	ipv6aBigInt.Set(ipv6.Address)
187
+	ipv6bBigInt := new(big.Int)
188
+	ipv6bBigInt.Set(ipv6b.Address)
189
+
190
+	return ipv6aBigInt.Cmp(ipv6bBigInt)
191
+}
192
+
193
+// CmpPort follows the Cmp() standard protocol and returns:
194
+//
195
+// - -1 If the receiver should sort first because its port is lower than arg
196
+// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr,
197
+//   regardless of type.
198
+// - 1 If the argument should sort first.
199
+func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int {
200
+	var saPort IPPort
201
+	switch v := sa.(type) {
202
+	case IPv4Addr:
203
+		saPort = v.Port
204
+	case IPv6Addr:
205
+		saPort = v.Port
206
+	default:
207
+		return sortDeferDecision
208
+	}
209
+
210
+	switch {
211
+	case ipv6.Port == saPort:
212
+		return sortDeferDecision
213
+	case ipv6.Port < saPort:
214
+		return sortReceiverBeforeArg
215
+	default:
216
+		return sortArgBeforeReceiver
217
+	}
218
+}
219
+
220
+// CmpRFC follows the Cmp() standard protocol and returns:
221
+//
222
+// - -1 If the receiver should sort first because it belongs to the RFC and its
223
+//   arg does not
224
+// - 0 if the receiver and arg both belong to the same RFC or neither do.
225
+// - 1 If the arg belongs to the RFC but receiver does not.
226
+func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
227
+	recvInRFC := IsRFC(rfcNum, ipv6)
228
+	ipv6b, ok := sa.(IPv6Addr)
229
+	if !ok {
230
+		// If the receiver is part of the desired RFC and the SockAddr
231
+		// argument is not, sort receiver before the non-IPv6 SockAddr.
232
+		// Conversely, if the receiver is not part of the RFC, punt on
233
+		// sorting and leave it for the next sorter.
234
+		if recvInRFC {
235
+			return sortReceiverBeforeArg
236
+		} else {
237
+			return sortDeferDecision
238
+		}
239
+	}
240
+
241
+	argInRFC := IsRFC(rfcNum, ipv6b)
242
+	switch {
243
+	case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
244
+		// If a and b both belong to the RFC, or neither belong to
245
+		// rfcNum, defer sorting to the next sorter.
246
+		return sortDeferDecision
247
+	case recvInRFC && !argInRFC:
248
+		return sortReceiverBeforeArg
249
+	default:
250
+		return sortArgBeforeReceiver
251
+	}
252
+}
253
+
254
+// Contains returns true if the SockAddr is contained within the receiver.
255
+func (ipv6 IPv6Addr) Contains(sa SockAddr) bool {
256
+	ipv6b, ok := sa.(IPv6Addr)
257
+	if !ok {
258
+		return false
259
+	}
260
+
261
+	return ipv6.ContainsNetwork(ipv6b)
262
+}
263
+
264
+// ContainsAddress returns true if the IPv6Address is contained within the
265
+// receiver.
266
+func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool {
267
+	xAddr := IPv6Addr{
268
+		Address: x,
269
+		Mask:    ipv6HostMask,
270
+	}
271
+
272
+	{
273
+		xIPv6 := xAddr.FirstUsable().(IPv6Addr)
274
+		yIPv6 := ipv6.FirstUsable().(IPv6Addr)
275
+		if xIPv6.CmpAddress(yIPv6) >= 1 {
276
+			return false
277
+		}
278
+	}
279
+
280
+	{
281
+		xIPv6 := xAddr.LastUsable().(IPv6Addr)
282
+		yIPv6 := ipv6.LastUsable().(IPv6Addr)
283
+		if xIPv6.CmpAddress(yIPv6) <= -1 {
284
+			return false
285
+		}
286
+	}
287
+	return true
288
+}
289
+
290
+// ContainsNetwork returns true if the network from IPv6Addr is contained within
291
+// the receiver.
292
+func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool {
293
+	{
294
+		xIPv6 := x.FirstUsable().(IPv6Addr)
295
+		yIPv6 := y.FirstUsable().(IPv6Addr)
296
+		if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 {
297
+			return false
298
+		}
299
+	}
300
+
301
+	{
302
+		xIPv6 := x.LastUsable().(IPv6Addr)
303
+		yIPv6 := y.LastUsable().(IPv6Addr)
304
+		if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 {
305
+			return false
306
+		}
307
+	}
308
+	return true
309
+}
310
+
311
+// DialPacketArgs returns the arguments required to be passed to
312
+// net.DialUDP().  If the Mask of ipv6 is not a /128 or the Port is 0,
313
+// DialPacketArgs() will fail.  See Host() to create an IPv6Addr with its
314
+// mask set to /128.
315
+func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) {
316
+	ipv6Mask := big.Int(*ipv6.Mask)
317
+	if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
318
+		return "udp6", ""
319
+	}
320
+	return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
321
+}
322
+
323
+// DialStreamArgs returns the arguments required to be passed to
324
+// net.DialTCP().  If the Mask of ipv6 is not a /128 or the Port is 0,
325
+// DialStreamArgs() will fail.  See Host() to create an IPv6Addr with its
326
+// mask set to /128.
327
+func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) {
328
+	ipv6Mask := big.Int(*ipv6.Mask)
329
+	if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
330
+		return "tcp6", ""
331
+	}
332
+	return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
333
+}
334
+
335
+// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
336
+func (ipv6a IPv6Addr) Equal(sa SockAddr) bool {
337
+	ipv6b, ok := sa.(IPv6Addr)
338
+	if !ok {
339
+		return false
340
+	}
341
+
342
+	if ipv6a.NetIP().String() != ipv6b.NetIP().String() {
343
+		return false
344
+	}
345
+
346
+	if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() {
347
+		return false
348
+	}
349
+
350
+	if ipv6a.Port != ipv6b.Port {
351
+		return false
352
+	}
353
+
354
+	return true
355
+}
356
+
357
+// FirstUsable returns an IPv6Addr set to the first address following the
358
+// network prefix.  The first usable address in a network is normally the
359
+// gateway and should not be used except by devices forwarding packets
360
+// between two administratively distinct networks (i.e. a router).  This
361
+// function does not discriminate against first usable vs "first address that
362
+// should be used."  For example, FirstUsable() on "2001:0db8::0003/64" would
363
+// return "2001:0db8::00011".
364
+func (ipv6 IPv6Addr) FirstUsable() IPAddr {
365
+	return IPv6Addr{
366
+		Address: IPv6Address(ipv6.NetworkAddress()),
367
+		Mask:    ipv6HostMask,
368
+	}
369
+}
370
+
371
+// Host returns a copy of ipv6 with its mask set to /128 so that it can be
372
+// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
373
+// ListenStreamArgs().
374
+func (ipv6 IPv6Addr) Host() IPAddr {
375
+	// Nothing should listen on a broadcast address.
376
+	return IPv6Addr{
377
+		Address: ipv6.Address,
378
+		Mask:    ipv6HostMask,
379
+		Port:    ipv6.Port,
380
+	}
381
+}
382
+
383
+// IPPort returns the Port number attached to the IPv6Addr
384
+func (ipv6 IPv6Addr) IPPort() IPPort {
385
+	return ipv6.Port
386
+}
387
+
388
+// LastUsable returns the last address in a given network.
389
+func (ipv6 IPv6Addr) LastUsable() IPAddr {
390
+	addr := new(big.Int)
391
+	addr.Set(ipv6.Address)
392
+
393
+	mask := new(big.Int)
394
+	mask.Set(ipv6.Mask)
395
+
396
+	negMask := new(big.Int)
397
+	negMask.Xor(ipv6HostMask, mask)
398
+
399
+	lastAddr := new(big.Int)
400
+	lastAddr.And(addr, mask)
401
+	lastAddr.Or(lastAddr, negMask)
402
+
403
+	return IPv6Addr{
404
+		Address: IPv6Address(lastAddr),
405
+		Mask:    ipv6HostMask,
406
+	}
407
+}
408
+
409
+// ListenPacketArgs returns the arguments required to be passed to
410
+// net.ListenUDP().  If the Mask of ipv6 is not a /128, ListenPacketArgs()
411
+// will fail.  See Host() to create an IPv6Addr with its mask set to /128.
412
+func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) {
413
+	ipv6Mask := big.Int(*ipv6.Mask)
414
+	if ipv6Mask.Cmp(ipv6HostMask) != 0 {
415
+		return "udp6", ""
416
+	}
417
+	return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
418
+}
419
+
420
+// ListenStreamArgs returns the arguments required to be passed to
421
+// net.ListenTCP().  If the Mask of ipv6 is not a /128, ListenStreamArgs()
422
+// will fail.  See Host() to create an IPv6Addr with its mask set to /128.
423
+func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) {
424
+	ipv6Mask := big.Int(*ipv6.Mask)
425
+	if ipv6Mask.Cmp(ipv6HostMask) != 0 {
426
+		return "tcp6", ""
427
+	}
428
+	return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
429
+}
430
+
431
+// Maskbits returns the number of network mask bits in a given IPv6Addr.  For
432
+// example, the Maskbits() of "2001:0db8::0003/64" would return 64.
433
+func (ipv6 IPv6Addr) Maskbits() int {
434
+	maskOnes, _ := ipv6.NetIPNet().Mask.Size()
435
+
436
+	return maskOnes
437
+}
438
+
439
+// MustIPv6Addr is a helper method that must return an IPv6Addr or panic on
440
+// invalid input.
441
+func MustIPv6Addr(addr string) IPv6Addr {
442
+	ipv6, err := NewIPv6Addr(addr)
443
+	if err != nil {
444
+		panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err))
445
+	}
446
+	return ipv6
447
+}
448
+
449
+// NetIP returns the address as a net.IP.
450
+func (ipv6 IPv6Addr) NetIP() *net.IP {
451
+	return bigIntToNetIPv6(ipv6.Address)
452
+}
453
+
454
+// NetIPMask create a new net.IPMask from the IPv6Addr.
455
+func (ipv6 IPv6Addr) NetIPMask() *net.IPMask {
456
+	ipv6Mask := make(net.IPMask, IPv6len)
457
+	m := big.Int(*ipv6.Mask)
458
+	copy(ipv6Mask, m.Bytes())
459
+	return &ipv6Mask
460
+}
461
+
462
+// Network returns a pointer to the net.IPNet within IPv4Addr receiver.
463
+func (ipv6 IPv6Addr) NetIPNet() *net.IPNet {
464
+	ipv6net := &net.IPNet{}
465
+	ipv6net.IP = make(net.IP, IPv6len)
466
+	copy(ipv6net.IP, *ipv6.NetIP())
467
+	ipv6net.Mask = *ipv6.NetIPMask()
468
+	return ipv6net
469
+}
470
+
471
+// Network returns the network prefix or network address for a given network.
472
+func (ipv6 IPv6Addr) Network() IPAddr {
473
+	return IPv6Addr{
474
+		Address: IPv6Address(ipv6.NetworkAddress()),
475
+		Mask:    ipv6.Mask,
476
+	}
477
+}
478
+
479
+// NetworkAddress returns an IPv6Network of the IPv6Addr's network address.
480
+func (ipv6 IPv6Addr) NetworkAddress() IPv6Network {
481
+	addr := new(big.Int)
482
+	addr.SetBytes((*ipv6.Address).Bytes())
483
+
484
+	mask := new(big.Int)
485
+	mask.SetBytes(*ipv6.NetIPMask())
486
+
487
+	netAddr := new(big.Int)
488
+	netAddr.And(addr, mask)
489
+
490
+	return IPv6Network(netAddr)
491
+}
492
+
493
+// Octets returns a slice of the 16 octets in an IPv6Addr's Address.  The
494
+// order of the bytes is big endian.
495
+func (ipv6 IPv6Addr) Octets() []int {
496
+	x := make([]int, IPv6len)
497
+	for i, b := range *bigIntToNetIPv6(ipv6.Address) {
498
+		x[i] = int(b)
499
+	}
500
+
501
+	return x
502
+}
503
+
504
+// String returns a string representation of the IPv6Addr
505
+func (ipv6 IPv6Addr) String() string {
506
+	if ipv6.Port != 0 {
507
+		return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
508
+	}
509
+
510
+	if ipv6.Maskbits() == 128 {
511
+		return ipv6.NetIP().String()
512
+	}
513
+
514
+	return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits())
515
+}
516
+
517
+// Type is used as a type switch and returns TypeIPv6
518
+func (IPv6Addr) Type() SockAddrType {
519
+	return TypeIPv6
520
+}
521
+
522
+// IPv6Attrs returns a list of attributes supported by the IPv6Addr type
523
+func IPv6Attrs() []AttrName {
524
+	return ipv6AddrAttrs
525
+}
526
+
527
+// IPv6AddrAttr returns a string representation of an attribute for the given
528
+// IPv6Addr.
529
+func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string {
530
+	fn, found := ipv6AddrAttrMap[selector]
531
+	if !found {
532
+		return ""
533
+	}
534
+
535
+	return fn(ipv6)
536
+}
537
+
538
+// ipv6AddrInit is called once at init()
539
+func ipv6AddrInit() {
540
+	// Sorted for human readability
541
+	ipv6AddrAttrs = []AttrName{
542
+		"size", // Same position as in IPv6 for output consistency
543
+		"uint128",
544
+	}
545
+
546
+	ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{
547
+		"size": func(ipv6 IPv6Addr) string {
548
+			netSize := big.NewInt(1)
549
+			netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits()))
550
+			return netSize.Text(10)
551
+		},
552
+		"uint128": func(ipv6 IPv6Addr) string {
553
+			b := big.Int(*ipv6.Address)
554
+			return b.Text(10)
555
+		},
556
+	}
557
+}
558
+
559
+// bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the
560
+// correctly padded values.
561
+func bigIntToNetIPv6(bi *big.Int) *net.IP {
562
+	x := make(net.IP, IPv6len)
563
+	ipv6Bytes := bi.Bytes()
564
+
565
+	// It's possibe for ipv6Bytes to be less than IPv6len bytes in size.  If
566
+	// they are different sizes we to pad the size of response.
567
+	if len(ipv6Bytes) < IPv6len {
568
+		buf := new(bytes.Buffer)
569
+		buf.Grow(IPv6len)
570
+
571
+		for i := len(ipv6Bytes); i < IPv6len; i++ {
572
+			if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil {
573
+				panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err))
574
+			}
575
+		}
576
+
577
+		for _, b := range ipv6Bytes {
578
+			if err := binary.Write(buf, binary.BigEndian, b); err != nil {
579
+				panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err))
580
+			}
581
+		}
582
+
583
+		ipv6Bytes = buf.Bytes()
584
+	}
585
+	i := copy(x, ipv6Bytes)
586
+	if i != IPv6len {
587
+		panic("IPv6 wrong size")
588
+	}
589
+	return &x
590
+}
0 591
new file mode 100644
... ...
@@ -0,0 +1,947 @@
0
+package sockaddr
1
+
2
+// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP
3
+// blocks.
4
+const ForwardingBlacklist = 4294967295
5
+
6
+// IsRFC tests to see if an SockAddr matches the specified RFC
7
+func IsRFC(rfcNum uint, sa SockAddr) bool {
8
+	rfcNetMap := KnownRFCs()
9
+	rfcNets, ok := rfcNetMap[rfcNum]
10
+	if !ok {
11
+		return false
12
+	}
13
+
14
+	var contained bool
15
+	for _, rfcNet := range rfcNets {
16
+		if rfcNet.Contains(sa) {
17
+			contained = true
18
+			break
19
+		}
20
+	}
21
+	return contained
22
+}
23
+
24
+// KnownRFCs returns an initial set of known RFCs.
25
+//
26
+// NOTE (sean@): As this list evolves over time, please submit patches to keep
27
+// this list current.  If something isn't right, inquire, as it may just be a
28
+// bug on my part.  Some of the inclusions were based on my judgement as to what
29
+// would be a useful value (e.g. RFC3330).
30
+//
31
+// Useful resources:
32
+//
33
+// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
34
+// * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml
35
+// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
36
+func KnownRFCs() map[uint]SockAddrs {
37
+	// NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a
38
+	// RADIX tree, but `ENOTIME`.  Patches welcome.
39
+	return map[uint]SockAddrs{
40
+		919: {
41
+			// [RFC919] Broadcasting Internet Datagrams
42
+			MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards
43
+		},
44
+		1122: {
45
+			// [RFC1122] Requirements for Internet Hosts -- Communication Layers
46
+			MustIPv4Addr("0.0.0.0/8"),   // [RFC1122], §3.2.1.3
47
+			MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3
48
+		},
49
+		1112: {
50
+			// [RFC1112] Host Extensions for IP Multicasting
51
+			MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses
52
+		},
53
+		1918: {
54
+			// [RFC1918] Address Allocation for Private Internets
55
+			MustIPv4Addr("10.0.0.0/8"),
56
+			MustIPv4Addr("172.16.0.0/12"),
57
+			MustIPv4Addr("192.168.0.0/16"),
58
+		},
59
+		2544: {
60
+			// [RFC2544] Benchmarking Methodology for Network
61
+			// Interconnect Devices
62
+			MustIPv4Addr("198.18.0.0/15"),
63
+		},
64
+		2765: {
65
+			// [RFC2765] Stateless IP/ICMP Translation Algorithm
66
+			// (SIIT) (obsoleted by RFCs 6145, which itself was
67
+			// later obsoleted by 7915).
68
+
69
+			// [RFC2765], §2.1 Addresses
70
+			MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"),
71
+		},
72
+		2928: {
73
+			// [RFC2928] Initial IPv6 Sub-TLA ID Assignments
74
+			MustIPv6Addr("2001::/16"), // Superblock
75
+			//MustIPv6Addr("2001:0000::/23"), // IANA
76
+			//MustIPv6Addr("2001:0200::/23"), // APNIC
77
+			//MustIPv6Addr("2001:0400::/23"), // ARIN
78
+			//MustIPv6Addr("2001:0600::/23"), // RIPE NCC
79
+			//MustIPv6Addr("2001:0800::/23"), // (future assignment)
80
+			// ...
81
+			//MustIPv6Addr("2001:FE00::/23"), // (future assignment)
82
+		},
83
+		3056: { // 6to4 address
84
+			// [RFC3056] Connection of IPv6 Domains via IPv4 Clouds
85
+
86
+			// [RFC3056], §2 IPv6 Prefix Allocation
87
+			MustIPv6Addr("2002::/16"),
88
+		},
89
+		3068: {
90
+			// [RFC3068] An Anycast Prefix for 6to4 Relay Routers
91
+			// (obsolete by RFC7526)
92
+
93
+			// [RFC3068], § 6to4 Relay anycast address
94
+			MustIPv4Addr("192.88.99.0/24"),
95
+
96
+			// [RFC3068], §2.5 6to4 IPv6 relay anycast address
97
+			//
98
+			// NOTE: /120 == 128-(32-24)
99
+			MustIPv6Addr("2002:c058:6301::/120"),
100
+		},
101
+		3171: {
102
+			// [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments
103
+			MustIPv4Addr("224.0.0.0/4"),
104
+		},
105
+		3330: {
106
+			// [RFC3330] Special-Use IPv4 Addresses
107
+
108
+			// Addresses in this block refer to source hosts on
109
+			// "this" network.  Address 0.0.0.0/32 may be used as a
110
+			// source address for this host on this network; other
111
+			// addresses within 0.0.0.0/8 may be used to refer to
112
+			// specified hosts on this network [RFC1700, page 4].
113
+			MustIPv4Addr("0.0.0.0/8"),
114
+
115
+			// 10.0.0.0/8 - This block is set aside for use in
116
+			// private networks.  Its intended use is documented in
117
+			// [RFC1918].  Addresses within this block should not
118
+			// appear on the public Internet.
119
+			MustIPv4Addr("10.0.0.0/8"),
120
+
121
+			// 14.0.0.0/8 - This block is set aside for assignments
122
+			// to the international system of Public Data Networks
123
+			// [RFC1700, page 181]. The registry of assignments
124
+			// within this block can be accessed from the "Public
125
+			// Data Network Numbers" link on the web page at
126
+			// http://www.iana.org/numbers.html.  Addresses within
127
+			// this block are assigned to users and should be
128
+			// treated as such.
129
+
130
+			// 24.0.0.0/8 - This block was allocated in early 1996
131
+			// for use in provisioning IP service over cable
132
+			// television systems.  Although the IANA initially was
133
+			// involved in making assignments to cable operators,
134
+			// this responsibility was transferred to American
135
+			// Registry for Internet Numbers (ARIN) in May 2001.
136
+			// Addresses within this block are assigned in the
137
+			// normal manner and should be treated as such.
138
+
139
+			// 39.0.0.0/8 - This block was used in the "Class A
140
+			// Subnet Experiment" that commenced in May 1995, as
141
+			// documented in [RFC1797].  The experiment has been
142
+			// completed and this block has been returned to the
143
+			// pool of addresses reserved for future allocation or
144
+			// assignment.  This block therefore no longer has a
145
+			// special use and is subject to allocation to a
146
+			// Regional Internet Registry for assignment in the
147
+			// normal manner.
148
+
149
+			// 127.0.0.0/8 - This block is assigned for use as the Internet host
150
+			// loopback address.  A datagram sent by a higher level protocol to an
151
+			// address anywhere within this block should loop back inside the host.
152
+			// This is ordinarily implemented using only 127.0.0.1/32 for loopback,
153
+			// but no addresses within this block should ever appear on any network
154
+			// anywhere [RFC1700, page 5].
155
+			MustIPv4Addr("127.0.0.0/8"),
156
+
157
+			// 128.0.0.0/16 - This block, corresponding to the
158
+			// numerically lowest of the former Class B addresses,
159
+			// was initially and is still reserved by the IANA.
160
+			// Given the present classless nature of the IP address
161
+			// space, the basis for the reservation no longer
162
+			// applies and addresses in this block are subject to
163
+			// future allocation to a Regional Internet Registry for
164
+			// assignment in the normal manner.
165
+
166
+			// 169.254.0.0/16 - This is the "link local" block.  It
167
+			// is allocated for communication between hosts on a
168
+			// single link.  Hosts obtain these addresses by
169
+			// auto-configuration, such as when a DHCP server may
170
+			// not be found.
171
+			MustIPv4Addr("169.254.0.0/16"),
172
+
173
+			// 172.16.0.0/12 - This block is set aside for use in
174
+			// private networks.  Its intended use is documented in
175
+			// [RFC1918].  Addresses within this block should not
176
+			// appear on the public Internet.
177
+			MustIPv4Addr("172.16.0.0/12"),
178
+
179
+			// 191.255.0.0/16 - This block, corresponding to the numerically highest
180
+			// to the former Class B addresses, was initially and is still reserved
181
+			// by the IANA.  Given the present classless nature of the IP address
182
+			// space, the basis for the reservation no longer applies and addresses
183
+			// in this block are subject to future allocation to a Regional Internet
184
+			// Registry for assignment in the normal manner.
185
+
186
+			// 192.0.0.0/24 - This block, corresponding to the
187
+			// numerically lowest of the former Class C addresses,
188
+			// was initially and is still reserved by the IANA.
189
+			// Given the present classless nature of the IP address
190
+			// space, the basis for the reservation no longer
191
+			// applies and addresses in this block are subject to
192
+			// future allocation to a Regional Internet Registry for
193
+			// assignment in the normal manner.
194
+
195
+			// 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in
196
+			// documentation and example code.  It is often used in conjunction with
197
+			// domain names example.com or example.net in vendor and protocol
198
+			// documentation.  Addresses within this block should not appear on the
199
+			// public Internet.
200
+			MustIPv4Addr("192.0.2.0/24"),
201
+
202
+			// 192.88.99.0/24 - This block is allocated for use as 6to4 relay
203
+			// anycast addresses, according to [RFC3068].
204
+			MustIPv4Addr("192.88.99.0/24"),
205
+
206
+			// 192.168.0.0/16 - This block is set aside for use in private networks.
207
+			// Its intended use is documented in [RFC1918].  Addresses within this
208
+			// block should not appear on the public Internet.
209
+			MustIPv4Addr("192.168.0.0/16"),
210
+
211
+			// 198.18.0.0/15 - This block has been allocated for use
212
+			// in benchmark tests of network interconnect devices.
213
+			// Its use is documented in [RFC2544].
214
+			MustIPv4Addr("198.18.0.0/15"),
215
+
216
+			// 223.255.255.0/24 - This block, corresponding to the
217
+			// numerically highest of the former Class C addresses,
218
+			// was initially and is still reserved by the IANA.
219
+			// Given the present classless nature of the IP address
220
+			// space, the basis for the reservation no longer
221
+			// applies and addresses in this block are subject to
222
+			// future allocation to a Regional Internet Registry for
223
+			// assignment in the normal manner.
224
+
225
+			// 224.0.0.0/4 - This block, formerly known as the Class
226
+			// D address space, is allocated for use in IPv4
227
+			// multicast address assignments.  The IANA guidelines
228
+			// for assignments from this space are described in
229
+			// [RFC3171].
230
+			MustIPv4Addr("224.0.0.0/4"),
231
+
232
+			// 240.0.0.0/4 - This block, formerly known as the Class E address
233
+			// space, is reserved.  The "limited broadcast" destination address
234
+			// 255.255.255.255 should never be forwarded outside the (sub-)net of
235
+			// the source.  The remainder of this space is reserved
236
+			// for future use.  [RFC1700, page 4]
237
+			MustIPv4Addr("240.0.0.0/4"),
238
+		},
239
+		3849: {
240
+			// [RFC3849] IPv6 Address Prefix Reserved for Documentation
241
+			MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations
242
+		},
243
+		3927: {
244
+			// [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses
245
+			MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection
246
+		},
247
+		4038: {
248
+			// [RFC4038] Application Aspects of IPv6 Transition
249
+
250
+			// [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node
251
+			MustIPv6Addr("0:0:0:0:0:ffff::/96"),
252
+		},
253
+		4193: {
254
+			// [RFC4193] Unique Local IPv6 Unicast Addresses
255
+			MustIPv6Addr("fc00::/7"),
256
+		},
257
+		4291: {
258
+			// [RFC4291] IP Version 6 Addressing Architecture
259
+
260
+			// [RFC4291], §2.5.2 The Unspecified Address
261
+			MustIPv6Addr("::/128"),
262
+
263
+			// [RFC4291], §2.5.3 The Loopback Address
264
+			MustIPv6Addr("::1/128"),
265
+
266
+			// [RFC4291], §2.5.5.1.  IPv4-Compatible IPv6 Address
267
+			MustIPv6Addr("::/96"),
268
+
269
+			// [RFC4291], §2.5.5.2.  IPv4-Mapped IPv6 Address
270
+			MustIPv6Addr("::ffff:0:0/96"),
271
+
272
+			// [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses
273
+			MustIPv6Addr("fe80::/10"),
274
+
275
+			// [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses
276
+			// (depreciated)
277
+			MustIPv6Addr("fec0::/10"),
278
+
279
+			// [RFC4291], §2.7 Multicast Addresses
280
+			MustIPv6Addr("ff00::/8"),
281
+
282
+			// IPv6 Multicast Information.
283
+			//
284
+			// In the following "table" below, `ff0x` is replaced
285
+			// with the following values depending on the scope of
286
+			// the query:
287
+			//
288
+			// IPv6 Multicast Scopes:
289
+			// * ff00/9 // reserved
290
+			// * ff01/9 // interface-local
291
+			// * ff02/9 // link-local
292
+			// * ff03/9 // realm-local
293
+			// * ff04/9 // admin-local
294
+			// * ff05/9 // site-local
295
+			// * ff08/9 // organization-local
296
+			// * ff0e/9 // global
297
+			// * ff0f/9 // reserved
298
+			//
299
+			// IPv6 Multicast Addresses:
300
+			// * ff0x::2 // All routers
301
+			// * ff02::5 // OSPFIGP
302
+			// * ff02::6 // OSPFIGP Designated Routers
303
+			// * ff02::9 // RIP Routers
304
+			// * ff02::a // EIGRP Routers
305
+			// * ff02::d // All PIM Routers
306
+			// * ff02::1a // All RPL Routers
307
+			// * ff0x::fb // mDNSv6
308
+			// * ff0x::101 // All Network Time Protocol (NTP) servers
309
+			// * ff02::1:1 // Link Name
310
+			// * ff02::1:2 // All-dhcp-agents
311
+			// * ff02::1:3 // Link-local Multicast Name Resolution
312
+			// * ff05::1:3 // All-dhcp-servers
313
+			// * ff02::1:ff00:0/104 // Solicited-node multicast address.
314
+			// * ff02::2:ff00:0/104 // Node Information Queries
315
+		},
316
+		4380: {
317
+			// [RFC4380] Teredo: Tunneling IPv6 over UDP through
318
+			// Network Address Translations (NATs)
319
+
320
+			// [RFC4380], §2.6 Global Teredo IPv6 Service Prefix
321
+			MustIPv6Addr("2001:0000::/32"),
322
+		},
323
+		4773: {
324
+			// [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block
325
+			MustIPv6Addr("2001:0000::/23"), // IANA
326
+		},
327
+		4843: {
328
+			// [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID)
329
+			MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations
330
+		},
331
+		5180: {
332
+			// [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices
333
+			MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations
334
+		},
335
+		5735: {
336
+			// [RFC5735] Special Use IPv4 Addresses
337
+			MustIPv4Addr("192.0.2.0/24"),    // TEST-NET-1
338
+			MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
339
+			MustIPv4Addr("203.0.113.0/24"),  // TEST-NET-3
340
+			MustIPv4Addr("198.18.0.0/15"),   // Benchmarks
341
+		},
342
+		5737: {
343
+			// [RFC5737] IPv4 Address Blocks Reserved for Documentation
344
+			MustIPv4Addr("192.0.2.0/24"),    // TEST-NET-1
345
+			MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
346
+			MustIPv4Addr("203.0.113.0/24"),  // TEST-NET-3
347
+		},
348
+		6052: {
349
+			// [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators
350
+			MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix
351
+		},
352
+		6333: {
353
+			// [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion
354
+			MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address
355
+		},
356
+		6598: {
357
+			// [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space
358
+			MustIPv4Addr("100.64.0.0/10"),
359
+		},
360
+		6666: {
361
+			// [RFC6666] A Discard Prefix for IPv6
362
+			MustIPv6Addr("0100::/64"),
363
+		},
364
+		6890: {
365
+			// [RFC6890] Special-Purpose IP Address Registries
366
+
367
+			// From "RFC6890 §2.2.1 Information Requirements":
368
+			/*
369
+			   The IPv4 and IPv6 Special-Purpose Address Registries maintain the
370
+			   following information regarding each entry:
371
+
372
+			   o  Address Block - A block of IPv4 or IPv6 addresses that has been
373
+			      registered for a special purpose.
374
+
375
+			   o  Name - A descriptive name for the special-purpose address block.
376
+
377
+			   o  RFC - The RFC through which the special-purpose address block was
378
+			      requested.
379
+
380
+			   o  Allocation Date - The date upon which the special-purpose address
381
+			      block was allocated.
382
+
383
+			   o  Termination Date - The date upon which the allocation is to be
384
+			      terminated.  This field is applicable for limited-use allocations
385
+			      only.
386
+
387
+			   o  Source - A boolean value indicating whether an address from the
388
+			      allocated special-purpose address block is valid when used as the
389
+			      source address of an IP datagram that transits two devices.
390
+
391
+			   o  Destination - A boolean value indicating whether an address from
392
+			      the allocated special-purpose address block is valid when used as
393
+			      the destination address of an IP datagram that transits two
394
+			      devices.
395
+
396
+			   o  Forwardable - A boolean value indicating whether a router may
397
+			      forward an IP datagram whose destination address is drawn from the
398
+			      allocated special-purpose address block between external
399
+			      interfaces.
400
+
401
+			   o  Global - A boolean value indicating whether an IP datagram whose
402
+			      destination address is drawn from the allocated special-purpose
403
+			      address block is forwardable beyond a specified administrative
404
+			      domain.
405
+
406
+			   o  Reserved-by-Protocol - A boolean value indicating whether the
407
+			      special-purpose address block is reserved by IP, itself.  This
408
+			      value is "TRUE" if the RFC that created the special-purpose
409
+			      address block requires all compliant IP implementations to behave
410
+			      in a special way when processing packets either to or from
411
+			      addresses contained by the address block.
412
+
413
+			   If the value of "Destination" is FALSE, the values of "Forwardable"
414
+			   and "Global" must also be false.
415
+			*/
416
+
417
+			/*+----------------------+----------------------------+
418
+			* | Attribute            | Value                      |
419
+			* +----------------------+----------------------------+
420
+			* | Address Block        | 0.0.0.0/8                  |
421
+			* | Name                 | "This host on this network"|
422
+			* | RFC                  | [RFC1122], Section 3.2.1.3 |
423
+			* | Allocation Date      | September 1981             |
424
+			* | Termination Date     | N/A                        |
425
+			* | Source               | True                       |
426
+			* | Destination          | False                      |
427
+			* | Forwardable          | False                      |
428
+			* | Global               | False                      |
429
+			* | Reserved-by-Protocol | True                       |
430
+			* +----------------------+----------------------------+*/
431
+			MustIPv4Addr("0.0.0.0/8"),
432
+
433
+			/*+----------------------+---------------+
434
+			* | Attribute            | Value         |
435
+			* +----------------------+---------------+
436
+			* | Address Block        | 10.0.0.0/8    |
437
+			* | Name                 | Private-Use   |
438
+			* | RFC                  | [RFC1918]     |
439
+			* | Allocation Date      | February 1996 |
440
+			* | Termination Date     | N/A           |
441
+			* | Source               | True          |
442
+			* | Destination          | True          |
443
+			* | Forwardable          | True          |
444
+			* | Global               | False         |
445
+			* | Reserved-by-Protocol | False         |
446
+			* +----------------------+---------------+ */
447
+			MustIPv4Addr("10.0.0.0/8"),
448
+
449
+			/*+----------------------+----------------------+
450
+			  | Attribute            | Value                |
451
+			  +----------------------+----------------------+
452
+			  | Address Block        | 100.64.0.0/10        |
453
+			  | Name                 | Shared Address Space |
454
+			  | RFC                  | [RFC6598]            |
455
+			  | Allocation Date      | April 2012           |
456
+			  | Termination Date     | N/A                  |
457
+			  | Source               | True                 |
458
+			  | Destination          | True                 |
459
+			  | Forwardable          | True                 |
460
+			  | Global               | False                |
461
+			  | Reserved-by-Protocol | False                |
462
+			  +----------------------+----------------------+*/
463
+			MustIPv4Addr("100.64.0.0/10"),
464
+
465
+			/*+----------------------+----------------------------+
466
+			  | Attribute            | Value                      |
467
+			  +----------------------+----------------------------+
468
+			  | Address Block        | 127.0.0.0/8                |
469
+			  | Name                 | Loopback                   |
470
+			  | RFC                  | [RFC1122], Section 3.2.1.3 |
471
+			  | Allocation Date      | September 1981             |
472
+			  | Termination Date     | N/A                        |
473
+			  | Source               | False [1]                  |
474
+			  | Destination          | False [1]                  |
475
+			  | Forwardable          | False [1]                  |
476
+			  | Global               | False [1]                  |
477
+			  | Reserved-by-Protocol | True                       |
478
+			  +----------------------+----------------------------+*/
479
+			// [1] Several protocols have been granted exceptions to
480
+			// this rule.  For examples, see [RFC4379] and
481
+			// [RFC5884].
482
+			MustIPv4Addr("127.0.0.0/8"),
483
+
484
+			/*+----------------------+----------------+
485
+			  | Attribute            | Value          |
486
+			  +----------------------+----------------+
487
+			  | Address Block        | 169.254.0.0/16 |
488
+			  | Name                 | Link Local     |
489
+			  | RFC                  | [RFC3927]      |
490
+			  | Allocation Date      | May 2005       |
491
+			  | Termination Date     | N/A            |
492
+			  | Source               | True           |
493
+			  | Destination          | True           |
494
+			  | Forwardable          | False          |
495
+			  | Global               | False          |
496
+			  | Reserved-by-Protocol | True           |
497
+			  +----------------------+----------------+*/
498
+			MustIPv4Addr("169.254.0.0/16"),
499
+
500
+			/*+----------------------+---------------+
501
+			  | Attribute            | Value         |
502
+			  +----------------------+---------------+
503
+			  | Address Block        | 172.16.0.0/12 |
504
+			  | Name                 | Private-Use   |
505
+			  | RFC                  | [RFC1918]     |
506
+			  | Allocation Date      | February 1996 |
507
+			  | Termination Date     | N/A           |
508
+			  | Source               | True          |
509
+			  | Destination          | True          |
510
+			  | Forwardable          | True          |
511
+			  | Global               | False         |
512
+			  | Reserved-by-Protocol | False         |
513
+			  +----------------------+---------------+*/
514
+			MustIPv4Addr("172.16.0.0/12"),
515
+
516
+			/*+----------------------+---------------------------------+
517
+			  | Attribute            | Value                           |
518
+			  +----------------------+---------------------------------+
519
+			  | Address Block        | 192.0.0.0/24 [2]                |
520
+			  | Name                 | IETF Protocol Assignments       |
521
+			  | RFC                  | Section 2.1 of this document    |
522
+			  | Allocation Date      | January 2010                    |
523
+			  | Termination Date     | N/A                             |
524
+			  | Source               | False                           |
525
+			  | Destination          | False                           |
526
+			  | Forwardable          | False                           |
527
+			  | Global               | False                           |
528
+			  | Reserved-by-Protocol | False                           |
529
+			  +----------------------+---------------------------------+*/
530
+			// [2] Not usable unless by virtue of a more specific
531
+			// reservation.
532
+			MustIPv4Addr("192.0.0.0/24"),
533
+
534
+			/*+----------------------+--------------------------------+
535
+			  | Attribute            | Value                          |
536
+			  +----------------------+--------------------------------+
537
+			  | Address Block        | 192.0.0.0/29                   |
538
+			  | Name                 | IPv4 Service Continuity Prefix |
539
+			  | RFC                  | [RFC6333], [RFC7335]           |
540
+			  | Allocation Date      | June 2011                      |
541
+			  | Termination Date     | N/A                            |
542
+			  | Source               | True                           |
543
+			  | Destination          | True                           |
544
+			  | Forwardable          | True                           |
545
+			  | Global               | False                          |
546
+			  | Reserved-by-Protocol | False                          |
547
+			  +----------------------+--------------------------------+*/
548
+			MustIPv4Addr("192.0.0.0/29"),
549
+
550
+			/*+----------------------+----------------------------+
551
+			  | Attribute            | Value                      |
552
+			  +----------------------+----------------------------+
553
+			  | Address Block        | 192.0.2.0/24               |
554
+			  | Name                 | Documentation (TEST-NET-1) |
555
+			  | RFC                  | [RFC5737]                  |
556
+			  | Allocation Date      | January 2010               |
557
+			  | Termination Date     | N/A                        |
558
+			  | Source               | False                      |
559
+			  | Destination          | False                      |
560
+			  | Forwardable          | False                      |
561
+			  | Global               | False                      |
562
+			  | Reserved-by-Protocol | False                      |
563
+			  +----------------------+----------------------------+*/
564
+			MustIPv4Addr("192.0.2.0/24"),
565
+
566
+			/*+----------------------+--------------------+
567
+			  | Attribute            | Value              |
568
+			  +----------------------+--------------------+
569
+			  | Address Block        | 192.88.99.0/24     |
570
+			  | Name                 | 6to4 Relay Anycast |
571
+			  | RFC                  | [RFC3068]          |
572
+			  | Allocation Date      | June 2001          |
573
+			  | Termination Date     | N/A                |
574
+			  | Source               | True               |
575
+			  | Destination          | True               |
576
+			  | Forwardable          | True               |
577
+			  | Global               | True               |
578
+			  | Reserved-by-Protocol | False              |
579
+			  +----------------------+--------------------+*/
580
+			MustIPv4Addr("192.88.99.0/24"),
581
+
582
+			/*+----------------------+----------------+
583
+			  | Attribute            | Value          |
584
+			  +----------------------+----------------+
585
+			  | Address Block        | 192.168.0.0/16 |
586
+			  | Name                 | Private-Use    |
587
+			  | RFC                  | [RFC1918]      |
588
+			  | Allocation Date      | February 1996  |
589
+			  | Termination Date     | N/A            |
590
+			  | Source               | True           |
591
+			  | Destination          | True           |
592
+			  | Forwardable          | True           |
593
+			  | Global               | False          |
594
+			  | Reserved-by-Protocol | False          |
595
+			  +----------------------+----------------+*/
596
+			MustIPv4Addr("192.168.0.0/16"),
597
+
598
+			/*+----------------------+---------------+
599
+			  | Attribute            | Value         |
600
+			  +----------------------+---------------+
601
+			  | Address Block        | 198.18.0.0/15 |
602
+			  | Name                 | Benchmarking  |
603
+			  | RFC                  | [RFC2544]     |
604
+			  | Allocation Date      | March 1999    |
605
+			  | Termination Date     | N/A           |
606
+			  | Source               | True          |
607
+			  | Destination          | True          |
608
+			  | Forwardable          | True          |
609
+			  | Global               | False         |
610
+			  | Reserved-by-Protocol | False         |
611
+			  +----------------------+---------------+*/
612
+			MustIPv4Addr("198.18.0.0/15"),
613
+
614
+			/*+----------------------+----------------------------+
615
+			  | Attribute            | Value                      |
616
+			  +----------------------+----------------------------+
617
+			  | Address Block        | 198.51.100.0/24            |
618
+			  | Name                 | Documentation (TEST-NET-2) |
619
+			  | RFC                  | [RFC5737]                  |
620
+			  | Allocation Date      | January 2010               |
621
+			  | Termination Date     | N/A                        |
622
+			  | Source               | False                      |
623
+			  | Destination          | False                      |
624
+			  | Forwardable          | False                      |
625
+			  | Global               | False                      |
626
+			  | Reserved-by-Protocol | False                      |
627
+			  +----------------------+----------------------------+*/
628
+			MustIPv4Addr("198.51.100.0/24"),
629
+
630
+			/*+----------------------+----------------------------+
631
+			  | Attribute            | Value                      |
632
+			  +----------------------+----------------------------+
633
+			  | Address Block        | 203.0.113.0/24             |
634
+			  | Name                 | Documentation (TEST-NET-3) |
635
+			  | RFC                  | [RFC5737]                  |
636
+			  | Allocation Date      | January 2010               |
637
+			  | Termination Date     | N/A                        |
638
+			  | Source               | False                      |
639
+			  | Destination          | False                      |
640
+			  | Forwardable          | False                      |
641
+			  | Global               | False                      |
642
+			  | Reserved-by-Protocol | False                      |
643
+			  +----------------------+----------------------------+*/
644
+			MustIPv4Addr("203.0.113.0/24"),
645
+
646
+			/*+----------------------+----------------------+
647
+			  | Attribute            | Value                |
648
+			  +----------------------+----------------------+
649
+			  | Address Block        | 240.0.0.0/4          |
650
+			  | Name                 | Reserved             |
651
+			  | RFC                  | [RFC1112], Section 4 |
652
+			  | Allocation Date      | August 1989          |
653
+			  | Termination Date     | N/A                  |
654
+			  | Source               | False                |
655
+			  | Destination          | False                |
656
+			  | Forwardable          | False                |
657
+			  | Global               | False                |
658
+			  | Reserved-by-Protocol | True                 |
659
+			  +----------------------+----------------------+*/
660
+			MustIPv4Addr("240.0.0.0/4"),
661
+
662
+			/*+----------------------+----------------------+
663
+			  | Attribute            | Value                |
664
+			  +----------------------+----------------------+
665
+			  | Address Block        | 255.255.255.255/32   |
666
+			  | Name                 | Limited Broadcast    |
667
+			  | RFC                  | [RFC0919], Section 7 |
668
+			  | Allocation Date      | October 1984         |
669
+			  | Termination Date     | N/A                  |
670
+			  | Source               | False                |
671
+			  | Destination          | True                 |
672
+			  | Forwardable          | False                |
673
+			  | Global               | False                |
674
+			  | Reserved-by-Protocol | False                |
675
+			  +----------------------+----------------------+*/
676
+			MustIPv4Addr("255.255.255.255/32"),
677
+
678
+			/*+----------------------+------------------+
679
+			  | Attribute            | Value            |
680
+			  +----------------------+------------------+
681
+			  | Address Block        | ::1/128          |
682
+			  | Name                 | Loopback Address |
683
+			  | RFC                  | [RFC4291]        |
684
+			  | Allocation Date      | February 2006    |
685
+			  | Termination Date     | N/A              |
686
+			  | Source               | False            |
687
+			  | Destination          | False            |
688
+			  | Forwardable          | False            |
689
+			  | Global               | False            |
690
+			  | Reserved-by-Protocol | True             |
691
+			  +----------------------+------------------+*/
692
+			MustIPv6Addr("::1/128"),
693
+
694
+			/*+----------------------+---------------------+
695
+			  | Attribute            | Value               |
696
+			  +----------------------+---------------------+
697
+			  | Address Block        | ::/128              |
698
+			  | Name                 | Unspecified Address |
699
+			  | RFC                  | [RFC4291]           |
700
+			  | Allocation Date      | February 2006       |
701
+			  | Termination Date     | N/A                 |
702
+			  | Source               | True                |
703
+			  | Destination          | False               |
704
+			  | Forwardable          | False               |
705
+			  | Global               | False               |
706
+			  | Reserved-by-Protocol | True                |
707
+			  +----------------------+---------------------+*/
708
+			MustIPv6Addr("::/128"),
709
+
710
+			/*+----------------------+---------------------+
711
+			  | Attribute            | Value               |
712
+			  +----------------------+---------------------+
713
+			  | Address Block        | 64:ff9b::/96        |
714
+			  | Name                 | IPv4-IPv6 Translat. |
715
+			  | RFC                  | [RFC6052]           |
716
+			  | Allocation Date      | October 2010        |
717
+			  | Termination Date     | N/A                 |
718
+			  | Source               | True                |
719
+			  | Destination          | True                |
720
+			  | Forwardable          | True                |
721
+			  | Global               | True                |
722
+			  | Reserved-by-Protocol | False               |
723
+			  +----------------------+---------------------+*/
724
+			MustIPv6Addr("64:ff9b::/96"),
725
+
726
+			/*+----------------------+---------------------+
727
+			  | Attribute            | Value               |
728
+			  +----------------------+---------------------+
729
+			  | Address Block        | ::ffff:0:0/96       |
730
+			  | Name                 | IPv4-mapped Address |
731
+			  | RFC                  | [RFC4291]           |
732
+			  | Allocation Date      | February 2006       |
733
+			  | Termination Date     | N/A                 |
734
+			  | Source               | False               |
735
+			  | Destination          | False               |
736
+			  | Forwardable          | False               |
737
+			  | Global               | False               |
738
+			  | Reserved-by-Protocol | True                |
739
+			  +----------------------+---------------------+*/
740
+			MustIPv6Addr("::ffff:0:0/96"),
741
+
742
+			/*+----------------------+----------------------------+
743
+			  | Attribute            | Value                      |
744
+			  +----------------------+----------------------------+
745
+			  | Address Block        | 100::/64                   |
746
+			  | Name                 | Discard-Only Address Block |
747
+			  | RFC                  | [RFC6666]                  |
748
+			  | Allocation Date      | June 2012                  |
749
+			  | Termination Date     | N/A                        |
750
+			  | Source               | True                       |
751
+			  | Destination          | True                       |
752
+			  | Forwardable          | True                       |
753
+			  | Global               | False                      |
754
+			  | Reserved-by-Protocol | False                      |
755
+			  +----------------------+----------------------------+*/
756
+			MustIPv6Addr("100::/64"),
757
+
758
+			/*+----------------------+---------------------------+
759
+			  | Attribute            | Value                     |
760
+			  +----------------------+---------------------------+
761
+			  | Address Block        | 2001::/23                 |
762
+			  | Name                 | IETF Protocol Assignments |
763
+			  | RFC                  | [RFC2928]                 |
764
+			  | Allocation Date      | September 2000            |
765
+			  | Termination Date     | N/A                       |
766
+			  | Source               | False[1]                  |
767
+			  | Destination          | False[1]                  |
768
+			  | Forwardable          | False[1]                  |
769
+			  | Global               | False[1]                  |
770
+			  | Reserved-by-Protocol | False                     |
771
+			  +----------------------+---------------------------+*/
772
+			// [1] Unless allowed by a more specific allocation.
773
+			MustIPv6Addr("2001::/16"),
774
+
775
+			/*+----------------------+----------------+
776
+			  | Attribute            | Value          |
777
+			  +----------------------+----------------+
778
+			  | Address Block        | 2001::/32      |
779
+			  | Name                 | TEREDO         |
780
+			  | RFC                  | [RFC4380]      |
781
+			  | Allocation Date      | January 2006   |
782
+			  | Termination Date     | N/A            |
783
+			  | Source               | True           |
784
+			  | Destination          | True           |
785
+			  | Forwardable          | True           |
786
+			  | Global               | False          |
787
+			  | Reserved-by-Protocol | False          |
788
+			  +----------------------+----------------+*/
789
+			// Covered by previous entry, included for completeness.
790
+			//
791
+			// MustIPv6Addr("2001::/16"),
792
+
793
+			/*+----------------------+----------------+
794
+			  | Attribute            | Value          |
795
+			  +----------------------+----------------+
796
+			  | Address Block        | 2001:2::/48    |
797
+			  | Name                 | Benchmarking   |
798
+			  | RFC                  | [RFC5180]      |
799
+			  | Allocation Date      | April 2008     |
800
+			  | Termination Date     | N/A            |
801
+			  | Source               | True           |
802
+			  | Destination          | True           |
803
+			  | Forwardable          | True           |
804
+			  | Global               | False          |
805
+			  | Reserved-by-Protocol | False          |
806
+			  +----------------------+----------------+*/
807
+			// Covered by previous entry, included for completeness.
808
+			//
809
+			// MustIPv6Addr("2001:2::/48"),
810
+
811
+			/*+----------------------+---------------+
812
+			  | Attribute            | Value         |
813
+			  +----------------------+---------------+
814
+			  | Address Block        | 2001:db8::/32 |
815
+			  | Name                 | Documentation |
816
+			  | RFC                  | [RFC3849]     |
817
+			  | Allocation Date      | July 2004     |
818
+			  | Termination Date     | N/A           |
819
+			  | Source               | False         |
820
+			  | Destination          | False         |
821
+			  | Forwardable          | False         |
822
+			  | Global               | False         |
823
+			  | Reserved-by-Protocol | False         |
824
+			  +----------------------+---------------+*/
825
+			// Covered by previous entry, included for completeness.
826
+			//
827
+			// MustIPv6Addr("2001:db8::/32"),
828
+
829
+			/*+----------------------+--------------+
830
+			  | Attribute            | Value        |
831
+			  +----------------------+--------------+
832
+			  | Address Block        | 2001:10::/28 |
833
+			  | Name                 | ORCHID       |
834
+			  | RFC                  | [RFC4843]    |
835
+			  | Allocation Date      | March 2007   |
836
+			  | Termination Date     | March 2014   |
837
+			  | Source               | False        |
838
+			  | Destination          | False        |
839
+			  | Forwardable          | False        |
840
+			  | Global               | False        |
841
+			  | Reserved-by-Protocol | False        |
842
+			  +----------------------+--------------+*/
843
+			// Covered by previous entry, included for completeness.
844
+			//
845
+			// MustIPv6Addr("2001:10::/28"),
846
+
847
+			/*+----------------------+---------------+
848
+			  | Attribute            | Value         |
849
+			  +----------------------+---------------+
850
+			  | Address Block        | 2002::/16 [2] |
851
+			  | Name                 | 6to4          |
852
+			  | RFC                  | [RFC3056]     |
853
+			  | Allocation Date      | February 2001 |
854
+			  | Termination Date     | N/A           |
855
+			  | Source               | True          |
856
+			  | Destination          | True          |
857
+			  | Forwardable          | True          |
858
+			  | Global               | N/A [2]       |
859
+			  | Reserved-by-Protocol | False         |
860
+			  +----------------------+---------------+*/
861
+			// [2] See [RFC3056] for details.
862
+			MustIPv6Addr("2002::/16"),
863
+
864
+			/*+----------------------+--------------+
865
+			  | Attribute            | Value        |
866
+			  +----------------------+--------------+
867
+			  | Address Block        | fc00::/7     |
868
+			  | Name                 | Unique-Local |
869
+			  | RFC                  | [RFC4193]    |
870
+			  | Allocation Date      | October 2005 |
871
+			  | Termination Date     | N/A          |
872
+			  | Source               | True         |
873
+			  | Destination          | True         |
874
+			  | Forwardable          | True         |
875
+			  | Global               | False        |
876
+			  | Reserved-by-Protocol | False        |
877
+			  +----------------------+--------------+*/
878
+			MustIPv6Addr("fc00::/7"),
879
+
880
+			/*+----------------------+-----------------------+
881
+			  | Attribute            | Value                 |
882
+			  +----------------------+-----------------------+
883
+			  | Address Block        | fe80::/10             |
884
+			  | Name                 | Linked-Scoped Unicast |
885
+			  | RFC                  | [RFC4291]             |
886
+			  | Allocation Date      | February 2006         |
887
+			  | Termination Date     | N/A                   |
888
+			  | Source               | True                  |
889
+			  | Destination          | True                  |
890
+			  | Forwardable          | False                 |
891
+			  | Global               | False                 |
892
+			  | Reserved-by-Protocol | True                  |
893
+			  +----------------------+-----------------------+*/
894
+			MustIPv6Addr("fe80::/10"),
895
+		},
896
+		7335: {
897
+			// [RFC7335] IPv4 Service Continuity Prefix
898
+			MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations
899
+		},
900
+		ForwardingBlacklist: { // Pseudo-RFC
901
+			// Blacklist of non-forwardable IP blocks taken from RFC6890
902
+			//
903
+			// TODO: the attributes for forwardable should be
904
+			// searcahble and embedded in the main list of RFCs
905
+			// above.
906
+			MustIPv4Addr("0.0.0.0/8"),
907
+			MustIPv4Addr("127.0.0.0/8"),
908
+			MustIPv4Addr("169.254.0.0/16"),
909
+			MustIPv4Addr("192.0.0.0/24"),
910
+			MustIPv4Addr("192.0.2.0/24"),
911
+			MustIPv4Addr("198.51.100.0/24"),
912
+			MustIPv4Addr("203.0.113.0/24"),
913
+			MustIPv4Addr("240.0.0.0/4"),
914
+			MustIPv4Addr("255.255.255.255/32"),
915
+			MustIPv6Addr("::1/128"),
916
+			MustIPv6Addr("::/128"),
917
+			MustIPv6Addr("::ffff:0:0/96"),
918
+
919
+			// There is no way of expressing a whitelist per RFC2928
920
+			// atm without creating a negative mask, which I don't
921
+			// want to do atm.
922
+			//MustIPv6Addr("2001::/23"),
923
+
924
+			MustIPv6Addr("2001:db8::/32"),
925
+			MustIPv6Addr("2001:10::/28"),
926
+			MustIPv6Addr("fe80::/10"),
927
+		},
928
+	}
929
+}
930
+
931
+// VisitAllRFCs iterates over all known RFCs and calls the visitor
932
+func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) {
933
+	rfcNetMap := KnownRFCs()
934
+
935
+	// Blacklist of faux-RFCs.  Don't show the world that we're abusing the
936
+	// RFC system in this library.
937
+	rfcBlacklist := map[uint]struct{}{
938
+		ForwardingBlacklist: {},
939
+	}
940
+
941
+	for rfcNum, sas := range rfcNetMap {
942
+		if _, found := rfcBlacklist[rfcNum]; !found {
943
+			fn(rfcNum, sas)
944
+		}
945
+	}
946
+}
0 947
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+package sockaddr
1
+
2
+// RouteInterface specifies an interface for obtaining memoized route table and
3
+// network information from a given OS.
4
+type RouteInterface interface {
5
+	// GetDefaultInterfaceName returns the name of the interface that has a
6
+	// default route or an error and an empty string if a problem was
7
+	// encountered.
8
+	GetDefaultInterfaceName() (string, error)
9
+}
10
+
11
+// VisitCommands visits each command used by the platform-specific RouteInfo
12
+// implementation.
13
+func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) {
14
+	for k, v := range ri.cmds {
15
+		cmds := append([]string(nil), v...)
16
+		fn(k, cmds)
17
+	}
18
+}
0 19
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+// +build darwin dragonfly freebsd netbsd openbsd
1
+
2
+package sockaddr
3
+
4
+import "os/exec"
5
+
6
+var cmds map[string][]string = map[string][]string{
7
+	"route": {"/sbin/route", "-n", "get", "default"},
8
+}
9
+
10
+type routeInfo struct {
11
+	cmds map[string][]string
12
+}
13
+
14
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
15
+// interface.
16
+func NewRouteInfo() (routeInfo, error) {
17
+	return routeInfo{
18
+		cmds: cmds,
19
+	}, nil
20
+}
21
+
22
+// GetDefaultInterfaceName returns the interface name attached to the default
23
+// route on the default interface.
24
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
25
+	out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
26
+	if err != nil {
27
+		return "", err
28
+	}
29
+
30
+	var ifName string
31
+	if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
32
+		return "", err
33
+	}
34
+	return ifName, nil
35
+}
0 36
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+// +build android nacl plan9
1
+
2
+package sockaddr
3
+
4
+import "errors"
5
+
6
+// getDefaultIfName is the default interface function for unsupported platforms.
7
+func getDefaultIfName() (string, error) {
8
+	return "", errors.New("No default interface found (unsupported platform)")
9
+}
0 10
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package sockaddr
1
+
2
+import (
3
+	"errors"
4
+	"os/exec"
5
+)
6
+
7
+var cmds map[string][]string = map[string][]string{
8
+	"ip": {"/sbin/ip", "route"},
9
+}
10
+
11
+type routeInfo struct {
12
+	cmds map[string][]string
13
+}
14
+
15
+// NewRouteInfo returns a Linux-specific implementation of the RouteInfo
16
+// interface.
17
+func NewRouteInfo() (routeInfo, error) {
18
+	return routeInfo{
19
+		cmds: cmds,
20
+	}, nil
21
+}
22
+
23
+// GetDefaultInterfaceName returns the interface name attached to the default
24
+// route on the default interface.
25
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
26
+	out, err := exec.Command(cmds["ip"][0], cmds["ip"][1:]...).Output()
27
+	if err != nil {
28
+		return "", err
29
+	}
30
+
31
+	var ifName string
32
+	if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil {
33
+		return "", errors.New("No default interface found")
34
+	}
35
+	return ifName, nil
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package sockaddr
1
+
2
+import (
3
+	"errors"
4
+	"os/exec"
5
+)
6
+
7
+var cmds map[string][]string = map[string][]string{
8
+	"route": {"/usr/sbin/route", "-n", "get", "default"},
9
+}
10
+
11
+type routeInfo struct {
12
+	cmds map[string][]string
13
+}
14
+
15
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
16
+// interface.
17
+func NewRouteInfo() (routeInfo, error) {
18
+	return routeInfo{
19
+		cmds: cmds,
20
+	}, nil
21
+}
22
+
23
+// GetDefaultInterfaceName returns the interface name attached to the default
24
+// route on the default interface.
25
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
26
+	out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
27
+	if err != nil {
28
+		return "", err
29
+	}
30
+
31
+	var ifName string
32
+	if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
33
+		return "", errors.New("No default interface found")
34
+	}
35
+	return ifName, nil
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+package sockaddr
1
+
2
+import "os/exec"
3
+
4
+var cmds map[string][]string = map[string][]string{
5
+	"netstat":  {"netstat", "-rn"},
6
+	"ipconfig": {"ipconfig"},
7
+}
8
+
9
+type routeInfo struct {
10
+	cmds map[string][]string
11
+}
12
+
13
+// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
14
+// interface.
15
+func NewRouteInfo() (routeInfo, error) {
16
+	return routeInfo{
17
+		cmds: cmds,
18
+	}, nil
19
+}
20
+
21
+// GetDefaultInterfaceName returns the interface name attached to the default
22
+// route on the default interface.
23
+func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
24
+	ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output()
25
+	if err != nil {
26
+		return "", err
27
+	}
28
+
29
+	ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output()
30
+	if err != nil {
31
+		return "", err
32
+	}
33
+
34
+	ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
35
+	if err != nil {
36
+		return "", err
37
+	}
38
+
39
+	return ifName, nil
40
+}
0 41
new file mode 100644
... ...
@@ -0,0 +1,178 @@
0
+package sockaddr
1
+
2
+import (
3
+	"fmt"
4
+	"strings"
5
+)
6
+
7
+type SockAddrType int
8
+type AttrName string
9
+
10
+const (
11
+	TypeUnknown SockAddrType = 0x0
12
+	TypeUnix                 = 0x1
13
+	TypeIPv4                 = 0x2
14
+	TypeIPv6                 = 0x4
15
+
16
+	// TypeIP is the union of TypeIPv4 and TypeIPv6
17
+	TypeIP = 0x6
18
+)
19
+
20
+type SockAddr interface {
21
+	// CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC
22
+	// networks, -1 if the receiver is contained within the RFC network, or
23
+	// 1 if the address is not contained within the RFC.
24
+	CmpRFC(rfcNum uint, sa SockAddr) int
25
+
26
+	// Contains returns true if the SockAddr arg is contained within the
27
+	// receiver
28
+	Contains(SockAddr) bool
29
+
30
+	// Equal allows for the comparison of two SockAddrs
31
+	Equal(SockAddr) bool
32
+
33
+	DialPacketArgs() (string, string)
34
+	DialStreamArgs() (string, string)
35
+	ListenPacketArgs() (string, string)
36
+	ListenStreamArgs() (string, string)
37
+
38
+	// String returns the string representation of SockAddr
39
+	String() string
40
+
41
+	// Type returns the SockAddrType
42
+	Type() SockAddrType
43
+}
44
+
45
+// sockAddrAttrMap is a map of the SockAddr type-specific attributes.
46
+var sockAddrAttrMap map[AttrName]func(SockAddr) string
47
+var sockAddrAttrs []AttrName
48
+
49
+func init() {
50
+	sockAddrInit()
51
+}
52
+
53
+// New creates a new SockAddr from the string.  The order in which New()
54
+// attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix.
55
+//
56
+// NOTE: New() relies on the heuristic wherein if the path begins with either a
57
+// '.'  or '/' character before creating a new UnixSock.  For UNIX sockets that
58
+// are absolute paths or are nested within a sub-directory, this works as
59
+// expected, however if the UNIX socket is contained in the current working
60
+// directory, this will fail unless the path begins with "./"
61
+// (e.g. "./my-local-socket").  Calls directly to NewUnixSock() do not suffer
62
+// this limitation.  Invalid IP addresses such as "256.0.0.0/-1" will run afoul
63
+// of this heuristic and be assumed to be a valid UNIX socket path (which they
64
+// are, but it is probably not what you want and you won't realize it until you
65
+// stat(2) the file system to discover it doesn't exist).
66
+func NewSockAddr(s string) (SockAddr, error) {
67
+	ipv4Addr, err := NewIPv4Addr(s)
68
+	if err == nil {
69
+		return ipv4Addr, nil
70
+	}
71
+
72
+	ipv6Addr, err := NewIPv6Addr(s)
73
+	if err == nil {
74
+		return ipv6Addr, nil
75
+	}
76
+
77
+	// Check to make sure the string begins with either a '.' or '/', or
78
+	// contains a '/'.
79
+	if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) {
80
+		unixSock, err := NewUnixSock(s)
81
+		if err == nil {
82
+			return unixSock, nil
83
+		}
84
+	}
85
+
86
+	return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s)
87
+}
88
+
89
+// ToIPAddr returns an IPAddr type or nil if the type conversion fails.
90
+func ToIPAddr(sa SockAddr) *IPAddr {
91
+	ipa, ok := sa.(IPAddr)
92
+	if !ok {
93
+		return nil
94
+	}
95
+	return &ipa
96
+}
97
+
98
+// ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails.
99
+func ToIPv4Addr(sa SockAddr) *IPv4Addr {
100
+	switch v := sa.(type) {
101
+	case IPv4Addr:
102
+		return &v
103
+	default:
104
+		return nil
105
+	}
106
+}
107
+
108
+// ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails.
109
+func ToIPv6Addr(sa SockAddr) *IPv6Addr {
110
+	switch v := sa.(type) {
111
+	case IPv6Addr:
112
+		return &v
113
+	default:
114
+		return nil
115
+	}
116
+}
117
+
118
+// ToUnixSock returns a UnixSock type or nil if the type conversion fails.
119
+func ToUnixSock(sa SockAddr) *UnixSock {
120
+	switch v := sa.(type) {
121
+	case UnixSock:
122
+		return &v
123
+	default:
124
+		return nil
125
+	}
126
+}
127
+
128
+// SockAddrAttr returns a string representation of an attribute for the given
129
+// SockAddr.
130
+func SockAddrAttr(sa SockAddr, selector AttrName) string {
131
+	fn, found := sockAddrAttrMap[selector]
132
+	if !found {
133
+		return ""
134
+	}
135
+
136
+	return fn(sa)
137
+}
138
+
139
+// String() for SockAddrType returns a string representation of the
140
+// SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown").
141
+func (sat SockAddrType) String() string {
142
+	switch sat {
143
+	case TypeIPv4:
144
+		return "IPv4"
145
+	case TypeIPv6:
146
+		return "IPv6"
147
+	// There is no concrete "IP" type.  Leaving here as a reminder.
148
+	// case TypeIP:
149
+	// 	return "IP"
150
+	case TypeUnix:
151
+		return "UNIX"
152
+	default:
153
+		panic("unsupported type")
154
+	}
155
+}
156
+
157
+// sockAddrInit is called once at init()
158
+func sockAddrInit() {
159
+	sockAddrAttrs = []AttrName{
160
+		"type", // type should be first
161
+		"string",
162
+	}
163
+
164
+	sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{
165
+		"string": func(sa SockAddr) string {
166
+			return sa.String()
167
+		},
168
+		"type": func(sa SockAddr) string {
169
+			return sa.Type().String()
170
+		},
171
+	}
172
+}
173
+
174
+// UnixSockAttrs returns a list of attributes supported by the UnixSock type
175
+func SockAddrAttrs() []AttrName {
176
+	return sockAddrAttrs
177
+}
0 178
new file mode 100644
... ...
@@ -0,0 +1,193 @@
0
+package sockaddr
1
+
2
+import (
3
+	"bytes"
4
+	"sort"
5
+)
6
+
7
+// SockAddrs is a slice of SockAddrs
8
+type SockAddrs []SockAddr
9
+
10
+func (s SockAddrs) Len() int      { return len(s) }
11
+func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
12
+
13
+// CmpAddrFunc is the function signature that must be met to be used in the
14
+// OrderedAddrBy multiAddrSorter
15
+type CmpAddrFunc func(p1, p2 *SockAddr) int
16
+
17
+// multiAddrSorter implements the Sort interface, sorting the SockAddrs within.
18
+type multiAddrSorter struct {
19
+	addrs SockAddrs
20
+	cmp   []CmpAddrFunc
21
+}
22
+
23
+// Sort sorts the argument slice according to the Cmp functions passed to
24
+// OrderedAddrBy.
25
+func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) {
26
+	ms.addrs = sockAddrs
27
+	sort.Sort(ms)
28
+}
29
+
30
+// OrderedAddrBy sorts SockAddr by the list of sort function pointers.
31
+func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter {
32
+	return &multiAddrSorter{
33
+		cmp: cmpFuncs,
34
+	}
35
+}
36
+
37
+// Len is part of sort.Interface.
38
+func (ms *multiAddrSorter) Len() int {
39
+	return len(ms.addrs)
40
+}
41
+
42
+// Less is part of sort.Interface. It is implemented by looping along the
43
+// Cmp() functions until it finds a comparison that is either less than,
44
+// equal to, or greater than.
45
+func (ms *multiAddrSorter) Less(i, j int) bool {
46
+	p, q := &ms.addrs[i], &ms.addrs[j]
47
+	// Try all but the last comparison.
48
+	var k int
49
+	for k = 0; k < len(ms.cmp)-1; k++ {
50
+		cmp := ms.cmp[k]
51
+		x := cmp(p, q)
52
+		switch x {
53
+		case -1:
54
+			// p < q, so we have a decision.
55
+			return true
56
+		case 1:
57
+			// p > q, so we have a decision.
58
+			return false
59
+		}
60
+		// p == q; try the next comparison.
61
+	}
62
+	// All comparisons to here said "equal", so just return whatever the
63
+	// final comparison reports.
64
+	switch ms.cmp[k](p, q) {
65
+	case -1:
66
+		return true
67
+	case 1:
68
+		return false
69
+	default:
70
+		// Still a tie! Now what?
71
+		return false
72
+	}
73
+}
74
+
75
+// Swap is part of sort.Interface.
76
+func (ms *multiAddrSorter) Swap(i, j int) {
77
+	ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i]
78
+}
79
+
80
+const (
81
+	// NOTE (sean@): These constants are here for code readability only and
82
+	// are sprucing up the code for readability purposes.  Some of the
83
+	// Cmp*() variants have confusing logic (especially when dealing with
84
+	// mixed-type comparisons) and this, I think, has made it easier to grok
85
+	// the code faster.
86
+	sortReceiverBeforeArg = -1
87
+	sortDeferDecision     = 0
88
+	sortArgBeforeReceiver = 1
89
+)
90
+
91
+// AscAddress is a sorting function to sort SockAddrs by their respective
92
+// address type.  Non-equal types are deferred in the sort.
93
+func AscAddress(p1Ptr, p2Ptr *SockAddr) int {
94
+	p1 := *p1Ptr
95
+	p2 := *p2Ptr
96
+
97
+	switch v := p1.(type) {
98
+	case IPv4Addr:
99
+		return v.CmpAddress(p2)
100
+	case IPv6Addr:
101
+		return v.CmpAddress(p2)
102
+	case UnixSock:
103
+		return v.CmpAddress(p2)
104
+	default:
105
+		return sortDeferDecision
106
+	}
107
+}
108
+
109
+// AscPort is a sorting function to sort SockAddrs by their respective address
110
+// type.  Non-equal types are deferred in the sort.
111
+func AscPort(p1Ptr, p2Ptr *SockAddr) int {
112
+	p1 := *p1Ptr
113
+	p2 := *p2Ptr
114
+
115
+	switch v := p1.(type) {
116
+	case IPv4Addr:
117
+		return v.CmpPort(p2)
118
+	case IPv6Addr:
119
+		return v.CmpPort(p2)
120
+	default:
121
+		return sortDeferDecision
122
+	}
123
+}
124
+
125
+// AscPrivate is a sorting function to sort "more secure" private values before
126
+// "more public" values.  Both IPv4 and IPv6 are compared against RFC6890
127
+// (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and
128
+// IPv6 includes RFC4193).
129
+func AscPrivate(p1Ptr, p2Ptr *SockAddr) int {
130
+	p1 := *p1Ptr
131
+	p2 := *p2Ptr
132
+
133
+	switch v := p1.(type) {
134
+	case IPv4Addr, IPv6Addr:
135
+		return v.CmpRFC(6890, p2)
136
+	default:
137
+		return sortDeferDecision
138
+	}
139
+}
140
+
141
+// AscNetworkSize is a sorting function to sort SockAddrs based on their network
142
+// size.  Non-equal types are deferred in the sort.
143
+func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int {
144
+	p1 := *p1Ptr
145
+	p2 := *p2Ptr
146
+	p1Type := p1.Type()
147
+	p2Type := p2.Type()
148
+
149
+	// Network size operations on non-IP types make no sense
150
+	if p1Type != p2Type && p1Type != TypeIP {
151
+		return sortDeferDecision
152
+	}
153
+
154
+	ipA := p1.(IPAddr)
155
+	ipB := p2.(IPAddr)
156
+
157
+	return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask()))
158
+}
159
+
160
+// AscType is a sorting function to sort "more secure" types before
161
+// "less-secure" types.
162
+func AscType(p1Ptr, p2Ptr *SockAddr) int {
163
+	p1 := *p1Ptr
164
+	p2 := *p2Ptr
165
+	p1Type := p1.Type()
166
+	p2Type := p2.Type()
167
+	switch {
168
+	case p1Type < p2Type:
169
+		return sortReceiverBeforeArg
170
+	case p1Type == p2Type:
171
+		return sortDeferDecision
172
+	case p1Type > p2Type:
173
+		return sortArgBeforeReceiver
174
+	default:
175
+		return sortDeferDecision
176
+	}
177
+}
178
+
179
+// FilterByType returns two lists: a list of matched and unmatched SockAddrs
180
+func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) {
181
+	matched = make(SockAddrs, 0, len(sas))
182
+	excluded = make(SockAddrs, 0, len(sas))
183
+
184
+	for _, sa := range sas {
185
+		if sa.Type()&type_ != 0 {
186
+			matched = append(matched, sa)
187
+		} else {
188
+			excluded = append(excluded, sa)
189
+		}
190
+	}
191
+	return matched, excluded
192
+}
0 193
new file mode 100644
... ...
@@ -0,0 +1,135 @@
0
+package sockaddr
1
+
2
+import (
3
+	"fmt"
4
+	"strings"
5
+)
6
+
7
+type UnixSock struct {
8
+	SockAddr
9
+	path string
10
+}
11
+type UnixSocks []*UnixSock
12
+
13
+// unixAttrMap is a map of the UnixSockAddr type-specific attributes.
14
+var unixAttrMap map[AttrName]func(UnixSock) string
15
+var unixAttrs []AttrName
16
+
17
+func init() {
18
+	unixAttrInit()
19
+}
20
+
21
+// NewUnixSock creates an UnixSock from a string path.  String can be in the
22
+// form of either URI-based string (e.g. `file:///etc/passwd`), an absolute
23
+// path (e.g. `/etc/passwd`), or a relative path (e.g. `./foo`).
24
+func NewUnixSock(s string) (ret UnixSock, err error) {
25
+	ret.path = s
26
+	return ret, nil
27
+}
28
+
29
+// CmpAddress follows the Cmp() standard protocol and returns:
30
+//
31
+// - -1 If the receiver should sort first because its name lexically sorts before arg
32
+// - 0 if the SockAddr arg is not a UnixSock, or is a UnixSock with the same path.
33
+// - 1 If the argument should sort first.
34
+func (us UnixSock) CmpAddress(sa SockAddr) int {
35
+	usb, ok := sa.(UnixSock)
36
+	if !ok {
37
+		return sortDeferDecision
38
+	}
39
+
40
+	return strings.Compare(us.Path(), usb.Path())
41
+}
42
+
43
+// DialPacketArgs returns the arguments required to be passed to net.DialUnix()
44
+// with the `unixgram` network type.
45
+func (us UnixSock) DialPacketArgs() (network, dialArgs string) {
46
+	return "unixgram", us.path
47
+}
48
+
49
+// DialStreamArgs returns the arguments required to be passed to net.DialUnix()
50
+// with the `unix` network type.
51
+func (us UnixSock) DialStreamArgs() (network, dialArgs string) {
52
+	return "unix", us.path
53
+}
54
+
55
+// Equal returns true if a SockAddr is equal to the receiving UnixSock.
56
+func (us UnixSock) Equal(sa SockAddr) bool {
57
+	usb, ok := sa.(UnixSock)
58
+	if !ok {
59
+		return false
60
+	}
61
+
62
+	if us.Path() != usb.Path() {
63
+		return false
64
+	}
65
+
66
+	return true
67
+}
68
+
69
+// ListenPacketArgs returns the arguments required to be passed to
70
+// net.ListenUnixgram() with the `unixgram` network type.
71
+func (us UnixSock) ListenPacketArgs() (network, dialArgs string) {
72
+	return "unixgram", us.path
73
+}
74
+
75
+// ListenStreamArgs returns the arguments required to be passed to
76
+// net.ListenUnix() with the `unix` network type.
77
+func (us UnixSock) ListenStreamArgs() (network, dialArgs string) {
78
+	return "unix", us.path
79
+}
80
+
81
+// MustUnixSock is a helper method that must return an UnixSock or panic on
82
+// invalid input.
83
+func MustUnixSock(addr string) UnixSock {
84
+	us, err := NewUnixSock(addr)
85
+	if err != nil {
86
+		panic(fmt.Sprintf("Unable to create a UnixSock from %+q: %v", addr, err))
87
+	}
88
+	return us
89
+}
90
+
91
+// Path returns the given path of the UnixSock
92
+func (us UnixSock) Path() string {
93
+	return us.path
94
+}
95
+
96
+// String returns the path of the UnixSock
97
+func (us UnixSock) String() string {
98
+	return fmt.Sprintf("%+q", us.path)
99
+}
100
+
101
+// Type is used as a type switch and returns TypeUnix
102
+func (UnixSock) Type() SockAddrType {
103
+	return TypeUnix
104
+}
105
+
106
+// UnixSockAttrs returns a list of attributes supported by the UnixSockAddr type
107
+func UnixSockAttrs() []AttrName {
108
+	return unixAttrs
109
+}
110
+
111
+// UnixSockAttr returns a string representation of an attribute for the given
112
+// UnixSock.
113
+func UnixSockAttr(us UnixSock, attrName AttrName) string {
114
+	fn, found := unixAttrMap[attrName]
115
+	if !found {
116
+		return ""
117
+	}
118
+
119
+	return fn(us)
120
+}
121
+
122
+// unixAttrInit is called once at init()
123
+func unixAttrInit() {
124
+	// Sorted for human readability
125
+	unixAttrs = []AttrName{
126
+		"path",
127
+	}
128
+
129
+	unixAttrMap = map[AttrName]func(us UnixSock) string{
130
+		"path": func(us UnixSock) string {
131
+			return us.Path()
132
+		},
133
+	}
134
+}
... ...
@@ -82,7 +82,7 @@ least one existing member in order to join the cluster. The new member
82 82
 does a full state sync with the existing member over TCP and begins gossiping its
83 83
 existence to the cluster.
84 84
 
85
-Gossip is done over UDP to a with a configurable but fixed fanout and interval.
85
+Gossip is done over UDP with a configurable but fixed fanout and interval.
86 86
 This ensures that network usage is constant with regards to number of nodes, as opposed to
87 87
 exponential growth that can occur with traditional heartbeat mechanisms.
88 88
 Complete state exchanges with a random node are done periodically over
89 89
new file mode 100644
... ...
@@ -0,0 +1,69 @@
0
+package memberlist
1
+
2
+import (
3
+	"sync"
4
+	"time"
5
+
6
+	"github.com/armon/go-metrics"
7
+)
8
+
9
+// awareness manages a simple metric for tracking the estimated health of the
10
+// local node. Health is primary the node's ability to respond in the soft
11
+// real-time manner required for correct health checking of other nodes in the
12
+// cluster.
13
+type awareness struct {
14
+	sync.RWMutex
15
+
16
+	// max is the upper threshold for the timeout scale (the score will be
17
+	// constrained to be from 0 <= score < max).
18
+	max int
19
+
20
+	// score is the current awareness score. Lower values are healthier and
21
+	// zero is the minimum value.
22
+	score int
23
+}
24
+
25
+// newAwareness returns a new awareness object.
26
+func newAwareness(max int) *awareness {
27
+	return &awareness{
28
+		max:   max,
29
+		score: 0,
30
+	}
31
+}
32
+
33
+// ApplyDelta takes the given delta and applies it to the score in a thread-safe
34
+// manner. It also enforces a floor of zero and a max of max, so deltas may not
35
+// change the overall score if it's railed at one of the extremes.
36
+func (a *awareness) ApplyDelta(delta int) {
37
+	a.Lock()
38
+	initial := a.score
39
+	a.score += delta
40
+	if a.score < 0 {
41
+		a.score = 0
42
+	} else if a.score > (a.max - 1) {
43
+		a.score = (a.max - 1)
44
+	}
45
+	final := a.score
46
+	a.Unlock()
47
+
48
+	if initial != final {
49
+		metrics.SetGauge([]string{"memberlist", "health", "score"}, float32(final))
50
+	}
51
+}
52
+
53
+// GetHealthScore returns the raw health score.
54
+func (a *awareness) GetHealthScore() int {
55
+	a.RLock()
56
+	score := a.score
57
+	a.RUnlock()
58
+	return score
59
+}
60
+
61
+// ScaleTimeout takes the given duration and scales it based on the current
62
+// score. Less healthyness will lead to longer timeouts.
63
+func (a *awareness) ScaleTimeout(timeout time.Duration) time.Duration {
64
+	a.RLock()
65
+	score := a.score
66
+	a.RUnlock()
67
+	return timeout * (time.Duration(score) + 1)
68
+}
... ...
@@ -11,10 +11,15 @@ type Config struct {
11 11
 	// The name of this node. This must be unique in the cluster.
12 12
 	Name string
13 13
 
14
+	// Transport is a hook for providing custom code to communicate with
15
+	// other nodes. If this is left nil, then memberlist will by default
16
+	// make a NetTransport using BindAddr and BindPort from this structure.
17
+	Transport Transport
18
+
14 19
 	// Configuration related to what address to bind to and ports to
15
-	// listen on. The port is used for both UDP and TCP gossip.
16
-	// It is assumed other nodes are running on this port, but they
17
-	// do not need to.
20
+	// listen on. The port is used for both UDP and TCP gossip. It is
21
+	// assumed other nodes are running on this port, but they do not need
22
+	// to.
18 23
 	BindAddr string
19 24
 	BindPort int
20 25
 
... ...
@@ -28,8 +33,11 @@ type Config struct {
28 28
 	// ProtocolVersionMax.
29 29
 	ProtocolVersion uint8
30 30
 
31
-	// TCPTimeout is the timeout for establishing a TCP connection with
32
-	// a remote node for a full state sync.
31
+	// TCPTimeout is the timeout for establishing a stream connection with
32
+	// a remote node for a full state sync, and for stream read and write
33
+	// operations. This is a legacy name for backwards compatibility, but
34
+	// should really be called StreamTimeout now that we have generalized
35
+	// the transport.
33 36
 	TCPTimeout time.Duration
34 37
 
35 38
 	// IndirectChecks is the number of nodes that will be asked to perform
... ...
@@ -63,6 +71,23 @@ type Config struct {
63 63
 	// still alive.
64 64
 	SuspicionMult int
65 65
 
66
+	// SuspicionMaxTimeoutMult is the multiplier applied to the
67
+	// SuspicionTimeout used as an upper bound on detection time. This max
68
+	// timeout is calculated using the formula:
69
+	//
70
+	// SuspicionMaxTimeout = SuspicionMaxTimeoutMult * SuspicionTimeout
71
+	//
72
+	// If everything is working properly, confirmations from other nodes will
73
+	// accelerate suspicion timers in a manner which will cause the timeout
74
+	// to reach the base SuspicionTimeout before that elapses, so this value
75
+	// will typically only come into play if a node is experiencing issues
76
+	// communicating with other nodes. It should be set to a something fairly
77
+	// large so that a node having problems will have a lot of chances to
78
+	// recover before falsely declaring other nodes as failed, but short
79
+	// enough for a legitimately isolated node to still make progress marking
80
+	// nodes failed in a reasonable amount of time.
81
+	SuspicionMaxTimeoutMult int
82
+
66 83
 	// PushPullInterval is the interval between complete state syncs.
67 84
 	// Complete state syncs are done with a single node over TCP and are
68 85
 	// quite expensive relative to standard gossiped messages. Setting this
... ...
@@ -91,6 +116,11 @@ type Config struct {
91 91
 	// indirect UDP pings.
92 92
 	DisableTcpPings bool
93 93
 
94
+	// AwarenessMaxMultiplier will increase the probe interval if the node
95
+	// becomes aware that it might be degraded and not meeting the soft real
96
+	// time requirements to reliably probe other nodes.
97
+	AwarenessMaxMultiplier int
98
+
94 99
 	// GossipInterval and GossipNodes are used to configure the gossip
95 100
 	// behavior of memberlist.
96 101
 	//
... ...
@@ -104,8 +134,12 @@ type Config struct {
104 104
 	// per GossipInterval. Increasing this number causes the gossip messages
105 105
 	// to propagate across the cluster more quickly at the expense of
106 106
 	// increased bandwidth.
107
-	GossipInterval time.Duration
108
-	GossipNodes    int
107
+	//
108
+	// GossipToTheDeadTime is the interval after which a node has died that
109
+	// we will still try to gossip to it. This gives it a chance to refute.
110
+	GossipInterval      time.Duration
111
+	GossipNodes         int
112
+	GossipToTheDeadTime time.Duration
109 113
 
110 114
 	// EnableCompression is used to control message compression. This can
111 115
 	// be used to reduce bandwidth usage at the cost of slightly more CPU
... ...
@@ -157,6 +191,20 @@ type Config struct {
157 157
 	// behavior for using LogOutput. You cannot specify both LogOutput and Logger
158 158
 	// at the same time.
159 159
 	Logger *log.Logger
160
+
161
+	// Size of Memberlist's internal channel which handles UDP messages. The
162
+	// size of this determines the size of the queue which Memberlist will keep
163
+	// while UDP messages are handled.
164
+	HandoffQueueDepth int
165
+
166
+	// Maximum number of bytes that memberlist will put in a packet (this
167
+	// will be for UDP packets by default with a NetTransport). A safe value
168
+	// for this is typically 1400 bytes (which is the default). However,
169
+	// depending on your network's MTU (Maximum Transmission Unit) you may
170
+	// be able to increase this to get more content into each gossip packet.
171
+	// This is a legacy name for backward compatibility but should really be
172
+	// called PacketBufferSize now that we have generalized the transport.
173
+	UDPBufferSize int
160 174
 }
161 175
 
162 176
 // DefaultLANConfig returns a sane set of configurations for Memberlist.
... ...
@@ -168,23 +216,26 @@ type Config struct {
168 168
 func DefaultLANConfig() *Config {
169 169
 	hostname, _ := os.Hostname()
170 170
 	return &Config{
171
-		Name:             hostname,
172
-		BindAddr:         "0.0.0.0",
173
-		BindPort:         7946,
174
-		AdvertiseAddr:    "",
175
-		AdvertisePort:    7946,
176
-		ProtocolVersion:  ProtocolVersion2Compatible,
177
-		TCPTimeout:       10 * time.Second,       // Timeout after 10 seconds
178
-		IndirectChecks:   3,                      // Use 3 nodes for the indirect ping
179
-		RetransmitMult:   4,                      // Retransmit a message 4 * log(N+1) nodes
180
-		SuspicionMult:    5,                      // Suspect a node for 5 * log(N+1) * Interval
181
-		PushPullInterval: 30 * time.Second,       // Low frequency
182
-		ProbeTimeout:     500 * time.Millisecond, // Reasonable RTT time for LAN
183
-		ProbeInterval:    1 * time.Second,        // Failure check every second
184
-		DisableTcpPings:  false,                  // TCP pings are safe, even with mixed versions
185
-
186
-		GossipNodes:    3,                      // Gossip to 3 nodes
187
-		GossipInterval: 200 * time.Millisecond, // Gossip more rapidly
171
+		Name:                    hostname,
172
+		BindAddr:                "0.0.0.0",
173
+		BindPort:                7946,
174
+		AdvertiseAddr:           "",
175
+		AdvertisePort:           7946,
176
+		ProtocolVersion:         ProtocolVersion2Compatible,
177
+		TCPTimeout:              10 * time.Second,       // Timeout after 10 seconds
178
+		IndirectChecks:          3,                      // Use 3 nodes for the indirect ping
179
+		RetransmitMult:          4,                      // Retransmit a message 4 * log(N+1) nodes
180
+		SuspicionMult:           5,                      // Suspect a node for 5 * log(N+1) * Interval
181
+		SuspicionMaxTimeoutMult: 6,                      // For 10k nodes this will give a max timeout of 120 seconds
182
+		PushPullInterval:        30 * time.Second,       // Low frequency
183
+		ProbeTimeout:            500 * time.Millisecond, // Reasonable RTT time for LAN
184
+		ProbeInterval:           1 * time.Second,        // Failure check every second
185
+		DisableTcpPings:         false,                  // TCP pings are safe, even with mixed versions
186
+		AwarenessMaxMultiplier:  8,                      // Probe interval backs off to 8 seconds
187
+
188
+		GossipNodes:         3,                      // Gossip to 3 nodes
189
+		GossipInterval:      200 * time.Millisecond, // Gossip more rapidly
190
+		GossipToTheDeadTime: 30 * time.Second,       // Same as push/pull
188 191
 
189 192
 		EnableCompression: true, // Enable compression by default
190 193
 
... ...
@@ -192,6 +243,9 @@ func DefaultLANConfig() *Config {
192 192
 		Keyring:   nil,
193 193
 
194 194
 		DNSConfigPath: "/etc/resolv.conf",
195
+
196
+		HandoffQueueDepth: 1024,
197
+		UDPBufferSize:     1400,
195 198
 	}
196 199
 }
197 200
 
... ...
@@ -207,6 +261,7 @@ func DefaultWANConfig() *Config {
207 207
 	conf.ProbeInterval = 5 * time.Second
208 208
 	conf.GossipNodes = 4 // Gossip less frequently, but to an additional node
209 209
 	conf.GossipInterval = 500 * time.Millisecond
210
+	conf.GossipToTheDeadTime = 60 * time.Second
210 211
 	return conf
211 212
 }
212 213
 
... ...
@@ -223,6 +278,7 @@ func DefaultLocalConfig() *Config {
223 223
 	conf.ProbeTimeout = 200 * time.Millisecond
224 224
 	conf.ProbeInterval = time.Second
225 225
 	conf.GossipInterval = 100 * time.Millisecond
226
+	conf.GossipToTheDeadTime = 15 * time.Second
226 227
 	return conf
227 228
 }
228 229
 
... ...
@@ -12,7 +12,7 @@ type Delegate interface {
12 12
 	// NotifyMsg is called when a user-data message is received.
13 13
 	// Care should be taken that this method does not block, since doing
14 14
 	// so would block the entire UDP packet receive loop. Additionally, the byte
15
-	// slice may be modified after the call returns, so it should be copied if needed.
15
+	// slice may be modified after the call returns, so it should be copied if needed
16 16
 	NotifyMsg([]byte)
17 17
 
18 18
 	// GetBroadcasts is called when user data messages can be broadcast.
... ...
@@ -58,6 +58,17 @@ func NewKeyring(keys [][]byte, primaryKey []byte) (*Keyring, error) {
58 58
 	return keyring, nil
59 59
 }
60 60
 
61
+// ValidateKey will check to see if the key is valid and returns an error if not.
62
+//
63
+// key should be either 16, 24, or 32 bytes to select AES-128,
64
+// AES-192, or AES-256.
65
+func ValidateKey(key []byte) error {
66
+	if l := len(key); l != 16 && l != 24 && l != 32 {
67
+		return fmt.Errorf("key size must be 16, 24 or 32 bytes")
68
+	}
69
+	return nil
70
+}
71
+
61 72
 // AddKey will install a new key on the ring. Adding a key to the ring will make
62 73
 // it available for use in decryption. If the key already exists on the ring,
63 74
 // this function will just return noop.
... ...
@@ -65,8 +76,8 @@ func NewKeyring(keys [][]byte, primaryKey []byte) (*Keyring, error) {
65 65
 // key should be either 16, 24, or 32 bytes to select AES-128,
66 66
 // AES-192, or AES-256.
67 67
 func (k *Keyring) AddKey(key []byte) error {
68
-	if l := len(key); l != 16 && l != 24 && l != 32 {
69
-		return fmt.Errorf("key size must be 16, 24 or 32 bytes")
68
+	if err := ValidateKey(key); err != nil {
69
+		return err
70 70
 	}
71 71
 
72 72
 	// No-op if key is already installed
... ...
@@ -25,6 +25,7 @@ import (
25 25
 	"time"
26 26
 
27 27
 	"github.com/hashicorp/go-multierror"
28
+	sockaddr "github.com/hashicorp/go-sockaddr"
28 29
 	"github.com/miekg/dns"
29 30
 )
30 31
 
... ...
@@ -39,13 +40,14 @@ type Memberlist struct {
39 39
 	leave          bool
40 40
 	leaveBroadcast chan struct{}
41 41
 
42
-	udpListener *net.UDPConn
43
-	tcpListener *net.TCPListener
44
-	handoff     chan msgHandoff
42
+	transport Transport
43
+	handoff   chan msgHandoff
45 44
 
46
-	nodeLock sync.RWMutex
47
-	nodes    []*nodeState          // Known nodes
48
-	nodeMap  map[string]*nodeState // Maps Addr.String() -> NodeState
45
+	nodeLock   sync.RWMutex
46
+	nodes      []*nodeState          // Known nodes
47
+	nodeMap    map[string]*nodeState // Maps Addr.String() -> NodeState
48
+	nodeTimers map[string]*suspicion // Maps Addr.String() -> suspicion timer
49
+	awareness  *awareness
49 50
 
50 51
 	tickerLock sync.Mutex
51 52
 	tickers    []*time.Ticker
... ...
@@ -61,7 +63,7 @@ type Memberlist struct {
61 61
 }
62 62
 
63 63
 // newMemberlist creates the network listeners.
64
-// Does not schedule execution of background maintenence.
64
+// Does not schedule execution of background maintenance.
65 65
 func newMemberlist(conf *Config) (*Memberlist, error) {
66 66
 	if conf.ProtocolVersion < ProtocolVersionMin {
67 67
 		return nil, fmt.Errorf("Protocol version '%d' too low. Must be in range: [%d, %d]",
... ...
@@ -88,25 +90,6 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
88 88
 		}
89 89
 	}
90 90
 
91
-	tcpAddr := &net.TCPAddr{IP: net.ParseIP(conf.BindAddr), Port: conf.BindPort}
92
-	tcpLn, err := net.ListenTCP("tcp", tcpAddr)
93
-	if err != nil {
94
-		return nil, fmt.Errorf("Failed to start TCP listener. Err: %s", err)
95
-	}
96
-	if conf.BindPort == 0 {
97
-		conf.BindPort = tcpLn.Addr().(*net.TCPAddr).Port
98
-	}
99
-
100
-	udpAddr := &net.UDPAddr{IP: net.ParseIP(conf.BindAddr), Port: conf.BindPort}
101
-	udpLn, err := net.ListenUDP("udp", udpAddr)
102
-	if err != nil {
103
-		tcpLn.Close()
104
-		return nil, fmt.Errorf("Failed to start UDP listener. Err: %s", err)
105
-	}
106
-
107
-	// Set the UDP receive window size
108
-	setUDPRecvBuf(udpLn)
109
-
110 91
 	if conf.LogOutput != nil && conf.Logger != nil {
111 92
 		return nil, fmt.Errorf("Cannot specify both LogOutput and Logger. Please choose a single log configuration setting.")
112 93
 	}
... ...
@@ -121,14 +104,37 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
121 121
 		logger = log.New(logDest, "", log.LstdFlags)
122 122
 	}
123 123
 
124
+	// Set up a network transport by default if a custom one wasn't given
125
+	// by the config.
126
+	transport := conf.Transport
127
+	if transport == nil {
128
+		nc := &NetTransportConfig{
129
+			BindAddrs: []string{conf.BindAddr},
130
+			BindPort:  conf.BindPort,
131
+			Logger:    logger,
132
+		}
133
+		nt, err := NewNetTransport(nc)
134
+		if err != nil {
135
+			return nil, fmt.Errorf("Could not set up network transport: %v", err)
136
+		}
137
+
138
+		if conf.BindPort == 0 {
139
+			port := nt.GetAutoBindPort()
140
+			conf.BindPort = port
141
+			logger.Printf("[DEBUG] Using dynamic bind port %d", port)
142
+		}
143
+		transport = nt
144
+	}
145
+
124 146
 	m := &Memberlist{
125 147
 		config:         conf,
126 148
 		shutdownCh:     make(chan struct{}),
127 149
 		leaveBroadcast: make(chan struct{}, 1),
128
-		udpListener:    udpLn,
129
-		tcpListener:    tcpLn,
130
-		handoff:        make(chan msgHandoff, 1024),
150
+		transport:      transport,
151
+		handoff:        make(chan msgHandoff, conf.HandoffQueueDepth),
131 152
 		nodeMap:        make(map[string]*nodeState),
153
+		nodeTimers:     make(map[string]*suspicion),
154
+		awareness:      newAwareness(conf.AwarenessMaxMultiplier),
132 155
 		ackHandlers:    make(map[uint32]*ackHandler),
133 156
 		broadcasts:     &TransmitLimitedQueue{RetransmitMult: conf.RetransmitMult},
134 157
 		logger:         logger,
... ...
@@ -136,9 +142,9 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
136 136
 	m.broadcasts.NumNodes = func() int {
137 137
 		return m.estNumNodes()
138 138
 	}
139
-	go m.tcpListen()
140
-	go m.udpListen()
141
-	go m.udpHandler()
139
+	go m.streamListen()
140
+	go m.packetListen()
141
+	go m.packetHandler()
142 142
 	return m, nil
143 143
 }
144 144
 
... ...
@@ -182,7 +188,8 @@ func (m *Memberlist) Join(existing []string) (int, error) {
182 182
 		}
183 183
 
184 184
 		for _, addr := range addrs {
185
-			if err := m.pushPullNode(addr.ip, addr.port, true); err != nil {
185
+			hp := joinHostPort(addr.ip.String(), addr.port)
186
+			if err := m.pushPullNode(hp, true); err != nil {
186 187
 				err = fmt.Errorf("Failed to join %s: %v", addr.ip, err)
187 188
 				errs = multierror.Append(errs, err)
188 189
 				m.logger.Printf("[DEBUG] memberlist: %v", err)
... ...
@@ -322,78 +329,30 @@ func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) {
322 322
 // as if we received an alive notification our own network channel for
323 323
 // ourself.
324 324
 func (m *Memberlist) setAlive() error {
325
-	var advertiseAddr []byte
326
-	var advertisePort int
327
-	if m.config.AdvertiseAddr != "" {
328
-		// If AdvertiseAddr is not empty, then advertise
329
-		// the given address and port.
330
-		ip := net.ParseIP(m.config.AdvertiseAddr)
331
-		if ip == nil {
332
-			return fmt.Errorf("Failed to parse advertise address!")
333
-		}
334
-
335
-		// Ensure IPv4 conversion if necessary
336
-		if ip4 := ip.To4(); ip4 != nil {
337
-			ip = ip4
338
-		}
339
-
340
-		advertiseAddr = ip
341
-		advertisePort = m.config.AdvertisePort
342
-	} else {
343
-		if m.config.BindAddr == "0.0.0.0" {
344
-			// Otherwise, if we're not bound to a specific IP,
345
-			//let's list the interfaces on this machine and use
346
-			// the first private IP we find.
347
-			addresses, err := net.InterfaceAddrs()
348
-			if err != nil {
349
-				return fmt.Errorf("Failed to get interface addresses! Err: %v", err)
350
-			}
351
-
352
-			// Find private IPv4 address
353
-			for _, rawAddr := range addresses {
354
-				var ip net.IP
355
-				switch addr := rawAddr.(type) {
356
-				case *net.IPAddr:
357
-					ip = addr.IP
358
-				case *net.IPNet:
359
-					ip = addr.IP
360
-				default:
361
-					continue
362
-				}
363
-
364
-				if ip.To4() == nil {
365
-					continue
366
-				}
367
-				if !IsPrivateIP(ip.String()) {
368
-					continue
369
-				}
370
-
371
-				advertiseAddr = ip
372
-				break
373
-			}
374
-
375
-			// Failed to find private IP, error
376
-			if advertiseAddr == nil {
377
-				return fmt.Errorf("No private IP address found, and explicit IP not provided")
378
-			}
379
-
380
-		} else {
381
-			// Use the IP that we're bound to.
382
-			addr := m.tcpListener.Addr().(*net.TCPAddr)
383
-			advertiseAddr = addr.IP
384
-		}
385
-
386
-		// Use the port we are bound to.
387
-		advertisePort = m.tcpListener.Addr().(*net.TCPAddr).Port
325
+	// Get the final advertise address from the transport, which may need
326
+	// to see which address we bound to.
327
+	addr, port, err := m.transport.FinalAdvertiseAddr(
328
+		m.config.AdvertiseAddr, m.config.AdvertisePort)
329
+	if err != nil {
330
+		return fmt.Errorf("Failed to get final advertise address: %v", err)
388 331
 	}
389 332
 
390 333
 	// Check if this is a public address without encryption
391
-	addrStr := net.IP(advertiseAddr).String()
392
-	if !IsPrivateIP(addrStr) && !isLoopbackIP(addrStr) && !m.config.EncryptionEnabled() {
334
+	ipAddr, err := sockaddr.NewIPAddr(addr.String())
335
+	if err != nil {
336
+		return fmt.Errorf("Failed to parse interface addresses: %v", err)
337
+	}
338
+	ifAddrs := []sockaddr.IfAddr{
339
+		sockaddr.IfAddr{
340
+			SockAddr: ipAddr,
341
+		},
342
+	}
343
+	_, publicIfs, err := sockaddr.IfByRFC("6890", ifAddrs)
344
+	if len(publicIfs) > 0 && !m.config.EncryptionEnabled() {
393 345
 		m.logger.Printf("[WARN] memberlist: Binding to public address without encryption!")
394 346
 	}
395 347
 
396
-	// Get the node meta data
348
+	// Set any metadata from the delegate.
397 349
 	var meta []byte
398 350
 	if m.config.Delegate != nil {
399 351
 		meta = m.config.Delegate.NodeMeta(MetaMaxSize)
... ...
@@ -405,8 +364,8 @@ func (m *Memberlist) setAlive() error {
405 405
 	a := alive{
406 406
 		Incarnation: m.nextIncarnation(),
407 407
 		Node:        m.config.Name,
408
-		Addr:        advertiseAddr,
409
-		Port:        uint16(advertisePort),
408
+		Addr:        addr,
409
+		Port:        uint16(port),
410 410
 		Meta:        meta,
411 411
 		Vsn: []uint8{
412 412
 			ProtocolVersionMin, ProtocolVersionMax, m.config.ProtocolVersion,
... ...
@@ -415,7 +374,6 @@ func (m *Memberlist) setAlive() error {
415 415
 		},
416 416
 	}
417 417
 	m.aliveNode(&a, nil, true)
418
-
419 418
 	return nil
420 419
 }
421 420
 
... ...
@@ -478,13 +436,8 @@ func (m *Memberlist) UpdateNode(timeout time.Duration) error {
478 478
 	return nil
479 479
 }
480 480
 
481
-// SendTo is used to directly send a message to another node, without
482
-// the use of the gossip mechanism. This will encode the message as a
483
-// user-data message, which a delegate will receive through NotifyMsg
484
-// The actual data is transmitted over UDP, which means this is a
485
-// best-effort transmission mechanism, and the maximum size of the
486
-// message is the size of a single UDP datagram, after compression.
487
-// This method is DEPRECATED in favor or SendToUDP
481
+// SendTo is deprecated in favor of SendBestEffort, which requires a node to
482
+// target.
488 483
 func (m *Memberlist) SendTo(to net.Addr, msg []byte) error {
489 484
 	// Encode as a user message
490 485
 	buf := make([]byte, 1, len(msg)+1)
... ...
@@ -492,36 +445,39 @@ func (m *Memberlist) SendTo(to net.Addr, msg []byte) error {
492 492
 	buf = append(buf, msg...)
493 493
 
494 494
 	// Send the message
495
-	return m.rawSendMsgUDP(to, buf)
495
+	return m.rawSendMsgPacket(to.String(), nil, buf)
496 496
 }
497 497
 
498
-// SendToUDP is used to directly send a message to another node, without
499
-// the use of the gossip mechanism. This will encode the message as a
500
-// user-data message, which a delegate will receive through NotifyMsg
501
-// The actual data is transmitted over UDP, which means this is a
502
-// best-effort transmission mechanism, and the maximum size of the
503
-// message is the size of a single UDP datagram, after compression
498
+// SendToUDP is deprecated in favor of SendBestEffort.
504 499
 func (m *Memberlist) SendToUDP(to *Node, msg []byte) error {
500
+	return m.SendBestEffort(to, msg)
501
+}
502
+
503
+// SendToTCP is deprecated in favor of SendReliable.
504
+func (m *Memberlist) SendToTCP(to *Node, msg []byte) error {
505
+	return m.SendReliable(to, msg)
506
+}
507
+
508
+// SendBestEffort uses the unreliable packet-oriented interface of the transport
509
+// to target a user message at the given node (this does not use the gossip
510
+// mechanism). The maximum size of the message depends on the configured
511
+// UDPBufferSize for this memberlist instance.
512
+func (m *Memberlist) SendBestEffort(to *Node, msg []byte) error {
505 513
 	// Encode as a user message
506 514
 	buf := make([]byte, 1, len(msg)+1)
507 515
 	buf[0] = byte(userMsg)
508 516
 	buf = append(buf, msg...)
509 517
 
510 518
 	// Send the message
511
-	destAddr := &net.UDPAddr{IP: to.Addr, Port: int(to.Port)}
512
-	return m.rawSendMsgUDP(destAddr, buf)
519
+	return m.rawSendMsgPacket(to.Address(), to, buf)
513 520
 }
514 521
 
515
-// SendToTCP is used to directly send a message to another node, without
516
-// the use of the gossip mechanism. This will encode the message as a
517
-// user-data message, which a delegate will receive through NotifyMsg
518
-// The actual data is transmitted over TCP, which means delivery
519
-// is guaranteed if no error is returned. There is no limit
520
-// to the size of the message
521
-func (m *Memberlist) SendToTCP(to *Node, msg []byte) error {
522
-	// Send the message
523
-	destAddr := &net.TCPAddr{IP: to.Addr, Port: int(to.Port)}
524
-	return m.sendTCPUserMsg(destAddr, msg)
522
+// SendReliable uses the reliable stream-oriented interface of the transport to
523
+// target a user message at the given node (this does not use the gossip
524
+// mechanism). Delivery is guaranteed if no error is returned, and there is no
525
+// limit on the size of the message.
526
+func (m *Memberlist) SendReliable(to *Node, msg []byte) error {
527
+	return m.sendUserMsg(to.Address(), msg)
525 528
 }
526 529
 
527 530
 // Members returns a list of all known live nodes. The node structures
... ...
@@ -625,6 +581,13 @@ func (m *Memberlist) anyAlive() bool {
625 625
 	return false
626 626
 }
627 627
 
628
+// GetHealthScore gives this instance's idea of how well it is meeting the soft
629
+// real-time requirements of the protocol. Lower numbers are better, and zero
630
+// means "totally healthy".
631
+func (m *Memberlist) GetHealthScore() int {
632
+	return m.awareness.GetHealthScore()
633
+}
634
+
628 635
 // ProtocolVersion returns the protocol version currently in use by
629 636
 // this memberlist.
630 637
 func (m *Memberlist) ProtocolVersion() uint8 {
... ...
@@ -649,10 +612,14 @@ func (m *Memberlist) Shutdown() error {
649 649
 		return nil
650 650
 	}
651 651
 
652
+	// Shut down the transport first, which should block until it's
653
+	// completely torn down. If we kill the memberlist-side handlers
654
+	// those I/O handlers might get stuck.
655
+	m.transport.Shutdown()
656
+
657
+	// Now tear down everything else.
652 658
 	m.shutdown = true
653 659
 	close(m.shutdownCh)
654 660
 	m.deschedule()
655
-	m.udpListener.Close()
656
-	m.tcpListener.Close()
657 661
 	return nil
658 662
 }
659 663
new file mode 100644
... ...
@@ -0,0 +1,121 @@
0
+package memberlist
1
+
2
+import (
3
+	"fmt"
4
+	"net"
5
+	"strconv"
6
+	"time"
7
+)
8
+
9
+// MockNetwork is used as a factory that produces MockTransport instances which
10
+// are uniquely addressed and wired up to talk to each other.
11
+type MockNetwork struct {
12
+	transports map[string]*MockTransport
13
+	port       int
14
+}
15
+
16
+// NewTransport returns a new MockTransport with a unique address, wired up to
17
+// talk to the other transports in the MockNetwork.
18
+func (n *MockNetwork) NewTransport() *MockTransport {
19
+	n.port += 1
20
+	addr := fmt.Sprintf("127.0.0.1:%d", n.port)
21
+	transport := &MockTransport{
22
+		net:      n,
23
+		addr:     &MockAddress{addr},
24
+		packetCh: make(chan *Packet),
25
+		streamCh: make(chan net.Conn),
26
+	}
27
+
28
+	if n.transports == nil {
29
+		n.transports = make(map[string]*MockTransport)
30
+	}
31
+	n.transports[addr] = transport
32
+	return transport
33
+}
34
+
35
+// MockAddress is a wrapper which adds the net.Addr interface to our mock
36
+// address scheme.
37
+type MockAddress struct {
38
+	addr string
39
+}
40
+
41
+// See net.Addr.
42
+func (a *MockAddress) Network() string {
43
+	return "mock"
44
+}
45
+
46
+// See net.Addr.
47
+func (a *MockAddress) String() string {
48
+	return a.addr
49
+}
50
+
51
+// MockTransport directly plumbs messages to other transports its MockNetwork.
52
+type MockTransport struct {
53
+	net      *MockNetwork
54
+	addr     *MockAddress
55
+	packetCh chan *Packet
56
+	streamCh chan net.Conn
57
+}
58
+
59
+// See Transport.
60
+func (t *MockTransport) FinalAdvertiseAddr(string, int) (net.IP, int, error) {
61
+	host, portStr, err := net.SplitHostPort(t.addr.String())
62
+	if err != nil {
63
+		return nil, 0, err
64
+	}
65
+
66
+	ip := net.ParseIP(host)
67
+	if ip == nil {
68
+		return nil, 0, fmt.Errorf("Failed to parse IP %q", host)
69
+	}
70
+
71
+	port, err := strconv.ParseInt(portStr, 10, 16)
72
+	if err != nil {
73
+		return nil, 0, err
74
+	}
75
+
76
+	return ip, int(port), nil
77
+}
78
+
79
+// See Transport.
80
+func (t *MockTransport) WriteTo(b []byte, addr string) (time.Time, error) {
81
+	dest, ok := t.net.transports[addr]
82
+	if !ok {
83
+		return time.Time{}, fmt.Errorf("No route to %q", addr)
84
+	}
85
+
86
+	now := time.Now()
87
+	dest.packetCh <- &Packet{
88
+		Buf:       b,
89
+		From:      t.addr,
90
+		Timestamp: now,
91
+	}
92
+	return now, nil
93
+}
94
+
95
+// See Transport.
96
+func (t *MockTransport) PacketCh() <-chan *Packet {
97
+	return t.packetCh
98
+}
99
+
100
+// See Transport.
101
+func (t *MockTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
102
+	dest, ok := t.net.transports[addr]
103
+	if !ok {
104
+		return nil, fmt.Errorf("No route to %q", addr)
105
+	}
106
+
107
+	p1, p2 := net.Pipe()
108
+	dest.streamCh <- p1
109
+	return p2, nil
110
+}
111
+
112
+// See Transport.
113
+func (t *MockTransport) StreamCh() <-chan net.Conn {
114
+	return t.streamCh
115
+}
116
+
117
+// See Transport.
118
+func (t *MockTransport) Shutdown() error {
119
+	return nil
120
+}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"bytes"
6 6
 	"encoding/binary"
7 7
 	"fmt"
8
+	"hash/crc32"
8 9
 	"io"
9 10
 	"net"
10 11
 	"time"
... ...
@@ -24,9 +25,15 @@ const (
24 24
 	// A memberlist speaking version 2 of the protocol will attempt
25 25
 	// to TCP ping another memberlist who understands version 3 or
26 26
 	// greater.
27
+	//
28
+	// Version 4 added support for nacks as part of indirect probes.
29
+	// A memberlist speaking version 2 of the protocol will expect
30
+	// nacks from another memberlist who understands version 4 or
31
+	// greater, and likewise nacks will be sent to memberlists who
32
+	// understand version 4 or greater.
27 33
 	ProtocolVersion2Compatible = 2
28 34
 
29
-	ProtocolVersionMax = 3
35
+	ProtocolVersionMax = 5
30 36
 )
31 37
 
32 38
 // messageType is an integer ID of a type of message that can be received
... ...
@@ -46,6 +53,8 @@ const (
46 46
 	userMsg // User mesg, not handled by us
47 47
 	compressMsg
48 48
 	encryptMsg
49
+	nackRespMsg
50
+	hasCrcMsg
49 51
 )
50 52
 
51 53
 // compressionType is used to specify the compression algorithm
... ...
@@ -59,9 +68,6 @@ const (
59 59
 	MetaMaxSize            = 512 // Maximum size for node meta data
60 60
 	compoundHeaderOverhead = 2   // Assumed header overhead
61 61
 	compoundOverhead       = 2   // Assumed overhead per entry in compoundHeader
62
-	udpBufSize             = 65536
63
-	udpRecvBuf             = 2 * 1024 * 1024
64
-	udpSendBuf             = 1400
65 62
 	userMsgOverhead        = 1
66 63
 	blockingWarning        = 10 * time.Millisecond // Warn if a UDP packet takes this long to process
67 64
 	maxPushStateBytes      = 10 * 1024 * 1024
... ...
@@ -83,6 +89,7 @@ type indirectPingReq struct {
83 83
 	Target []byte
84 84
 	Port   uint16
85 85
 	Node   string
86
+	Nack   bool // true if we'd like a nack back
86 87
 }
87 88
 
88 89
 // ack response is sent for a ping
... ...
@@ -91,6 +98,13 @@ type ackResp struct {
91 91
 	Payload []byte
92 92
 }
93 93
 
94
+// nack response is sent for an indirect ping when the pinger doesn't hear from
95
+// the ping-ee within the configured timeout. This lets the original node know
96
+// that the indirect ping attempt happened but didn't succeed.
97
+type nackResp struct {
98
+	SeqNo uint32
99
+}
100
+
94 101
 // suspect is broadcast when we suspect a node is dead
95 102
 type suspect struct {
96 103
 	Incarnation uint32
... ...
@@ -121,7 +135,7 @@ type dead struct {
121 121
 }
122 122
 
123 123
 // pushPullHeader is used to inform the
124
-// otherside how many states we are transfering
124
+// otherside how many states we are transferring
125 125
 type pushPullHeader struct {
126 126
 	Nodes        int
127 127
 	UserStateLen int  // Encodes the byte lengh of user state
... ...
@@ -134,7 +148,7 @@ type userMsgHeader struct {
134 134
 }
135 135
 
136 136
 // pushNodeState is used for pushPullReq when we are
137
-// transfering out node states
137
+// transferring out node states
138 138
 type pushNodeState struct {
139 139
 	Name        string
140 140
 	Addr        []byte
... ...
@@ -169,45 +183,33 @@ func (m *Memberlist) encryptionVersion() encryptionVersion {
169 169
 	}
170 170
 }
171 171
 
172
-// setUDPRecvBuf is used to resize the UDP receive window. The function
173
-// attempts to set the read buffer to `udpRecvBuf` but backs off until
174
-// the read buffer can be set.
175
-func setUDPRecvBuf(c *net.UDPConn) {
176
-	size := udpRecvBuf
172
+// streamListen is a long running goroutine that pulls incoming streams from the
173
+// transport and hands them off for processing.
174
+func (m *Memberlist) streamListen() {
177 175
 	for {
178
-		if err := c.SetReadBuffer(size); err == nil {
179
-			break
180
-		}
181
-		size = size / 2
182
-	}
183
-}
176
+		select {
177
+		case conn := <-m.transport.StreamCh():
178
+			go m.handleConn(conn)
184 179
 
185
-// tcpListen listens for and handles incoming connections
186
-func (m *Memberlist) tcpListen() {
187
-	for {
188
-		conn, err := m.tcpListener.AcceptTCP()
189
-		if err != nil {
190
-			if m.shutdown {
191
-				break
192
-			}
193
-			m.logger.Printf("[ERR] memberlist: Error accepting TCP connection: %s", err)
194
-			continue
180
+		case <-m.shutdownCh:
181
+			return
195 182
 		}
196
-		go m.handleConn(conn)
197 183
 	}
198 184
 }
199 185
 
200
-// handleConn handles a single incoming TCP connection
201
-func (m *Memberlist) handleConn(conn *net.TCPConn) {
202
-	m.logger.Printf("[DEBUG] memberlist: TCP connection %s", LogConn(conn))
186
+// handleConn handles a single incoming stream connection from the transport.
187
+func (m *Memberlist) handleConn(conn net.Conn) {
188
+	m.logger.Printf("[DEBUG] memberlist: Stream connection %s", LogConn(conn))
203 189
 
204 190
 	defer conn.Close()
205 191
 	metrics.IncrCounter([]string{"memberlist", "tcp", "accept"}, 1)
206 192
 
207 193
 	conn.SetDeadline(time.Now().Add(m.config.TCPTimeout))
208
-	msgType, bufConn, dec, err := m.readTCP(conn)
194
+	msgType, bufConn, dec, err := m.readStream(conn)
209 195
 	if err != nil {
210
-		m.logger.Printf("[ERR] memberlist: failed to receive: %s %s", err, LogConn(conn))
196
+		if err != io.EOF {
197
+			m.logger.Printf("[ERR] memberlist: failed to receive: %s %s", err, LogConn(conn))
198
+		}
211 199
 		return
212 200
 	}
213 201
 
... ...
@@ -235,7 +237,7 @@ func (m *Memberlist) handleConn(conn *net.TCPConn) {
235 235
 	case pingMsg:
236 236
 		var p ping
237 237
 		if err := dec.Decode(&p); err != nil {
238
-			m.logger.Printf("[ERR] memberlist: Failed to decode TCP ping: %s %s", err, LogConn(conn))
238
+			m.logger.Printf("[ERR] memberlist: Failed to decode ping: %s %s", err, LogConn(conn))
239 239
 			return
240 240
 		}
241 241
 
... ...
@@ -247,13 +249,13 @@ func (m *Memberlist) handleConn(conn *net.TCPConn) {
247 247
 		ack := ackResp{p.SeqNo, nil}
248 248
 		out, err := encode(ackRespMsg, &ack)
249 249
 		if err != nil {
250
-			m.logger.Printf("[ERR] memberlist: Failed to encode TCP ack: %s", err)
250
+			m.logger.Printf("[ERR] memberlist: Failed to encode ack: %s", err)
251 251
 			return
252 252
 		}
253 253
 
254
-		err = m.rawSendMsgTCP(conn, out.Bytes())
254
+		err = m.rawSendMsgStream(conn, out.Bytes())
255 255
 		if err != nil {
256
-			m.logger.Printf("[ERR] memberlist: Failed to send TCP ack: %s %s", err, LogConn(conn))
256
+			m.logger.Printf("[ERR] memberlist: Failed to send ack: %s %s", err, LogConn(conn))
257 257
 			return
258 258
 		}
259 259
 	default:
... ...
@@ -261,49 +263,17 @@ func (m *Memberlist) handleConn(conn *net.TCPConn) {
261 261
 	}
262 262
 }
263 263
 
264
-// udpListen listens for and handles incoming UDP packets
265
-func (m *Memberlist) udpListen() {
266
-	var n int
267
-	var addr net.Addr
268
-	var err error
269
-	var lastPacket time.Time
264
+// packetListen is a long running goroutine that pulls packets out of the
265
+// transport and hands them off for processing.
266
+func (m *Memberlist) packetListen() {
270 267
 	for {
271
-		// Do a check for potentially blocking operations
272
-		if !lastPacket.IsZero() && time.Now().Sub(lastPacket) > blockingWarning {
273
-			diff := time.Now().Sub(lastPacket)
274
-			m.logger.Printf(
275
-				"[DEBUG] memberlist: Potential blocking operation. Last command took %v",
276
-				diff)
277
-		}
278
-
279
-		// Create a new buffer
280
-		// TODO: Use Sync.Pool eventually
281
-		buf := make([]byte, udpBufSize)
282
-
283
-		// Read a packet
284
-		n, addr, err = m.udpListener.ReadFrom(buf)
285
-		if err != nil {
286
-			if m.shutdown {
287
-				break
288
-			}
289
-			m.logger.Printf("[ERR] memberlist: Error reading UDP packet: %s", err)
290
-			continue
291
-		}
292
-
293
-		// Capture the reception time of the packet as close to the
294
-		// system calls as possible.
295
-		lastPacket = time.Now()
268
+		select {
269
+		case packet := <-m.transport.PacketCh():
270
+			m.ingestPacket(packet.Buf, packet.From, packet.Timestamp)
296 271
 
297
-		// Check the length
298
-		if n < 1 {
299
-			m.logger.Printf("[ERR] memberlist: UDP packet too short (%d bytes) %s",
300
-				len(buf), LogAddress(addr))
301
-			continue
272
+		case <-m.shutdownCh:
273
+			return
302 274
 		}
303
-
304
-		// Ingest this packet
305
-		metrics.IncrCounter([]string{"memberlist", "udp", "received"}, float32(n))
306
-		m.ingestPacket(buf[:n], addr, lastPacket)
307 275
 	}
308 276
 }
309 277
 
... ...
@@ -321,8 +291,18 @@ func (m *Memberlist) ingestPacket(buf []byte, from net.Addr, timestamp time.Time
321 321
 		buf = plain
322 322
 	}
323 323
 
324
-	// Handle the command
325
-	m.handleCommand(buf, from, timestamp)
324
+	// See if there's a checksum included to verify the contents of the message
325
+	if len(buf) >= 5 && messageType(buf[0]) == hasCrcMsg {
326
+		crc := crc32.ChecksumIEEE(buf[5:])
327
+		expected := binary.BigEndian.Uint32(buf[1:5])
328
+		if crc != expected {
329
+			m.logger.Printf("[WARN] memberlist: Got invalid checksum for UDP packet: %x, %x", crc, expected)
330
+			return
331
+		}
332
+		m.handleCommand(buf[5:], from, timestamp)
333
+	} else {
334
+		m.handleCommand(buf, from, timestamp)
335
+	}
326 336
 }
327 337
 
328 338
 func (m *Memberlist) handleCommand(buf []byte, from net.Addr, timestamp time.Time) {
... ...
@@ -343,6 +323,8 @@ func (m *Memberlist) handleCommand(buf []byte, from net.Addr, timestamp time.Tim
343 343
 		m.handleIndirectPing(buf, from)
344 344
 	case ackRespMsg:
345 345
 		m.handleAck(buf, from, timestamp)
346
+	case nackRespMsg:
347
+		m.handleNack(buf, from)
346 348
 
347 349
 	case suspectMsg:
348 350
 		fallthrough
... ...
@@ -354,18 +336,18 @@ func (m *Memberlist) handleCommand(buf []byte, from net.Addr, timestamp time.Tim
354 354
 		select {
355 355
 		case m.handoff <- msgHandoff{msgType, buf, from}:
356 356
 		default:
357
-			m.logger.Printf("[WARN] memberlist: UDP handler queue full, dropping message (%d) %s", msgType, LogAddress(from))
357
+			m.logger.Printf("[WARN] memberlist: handler queue full, dropping message (%d) %s", msgType, LogAddress(from))
358 358
 		}
359 359
 
360 360
 	default:
361
-		m.logger.Printf("[ERR] memberlist: UDP msg type (%d) not supported %s", msgType, LogAddress(from))
361
+		m.logger.Printf("[ERR] memberlist: msg type (%d) not supported %s", msgType, LogAddress(from))
362 362
 	}
363 363
 }
364 364
 
365
-// udpHandler processes messages received over UDP, but is decoupled
366
-// from the listener to avoid blocking the listener which may cause
367
-// ping/ack messages to be delayed.
368
-func (m *Memberlist) udpHandler() {
365
+// packetHandler is a long running goroutine that processes messages received
366
+// over the packet interface, but is decoupled from the listener to avoid
367
+// blocking the listener which may cause ping/ack messages to be delayed.
368
+func (m *Memberlist) packetHandler() {
369 369
 	for {
370 370
 		select {
371 371
 		case msg := <-m.handoff:
... ...
@@ -383,7 +365,7 @@ func (m *Memberlist) udpHandler() {
383 383
 			case userMsg:
384 384
 				m.handleUser(buf, from)
385 385
 			default:
386
-				m.logger.Printf("[ERR] memberlist: UDP msg type (%d) not supported %s (handler)", msgType, LogAddress(from))
386
+				m.logger.Printf("[ERR] memberlist: Message type (%d) not supported %s (packet handler)", msgType, LogAddress(from))
387 387
 			}
388 388
 
389 389
 		case <-m.shutdownCh:
... ...
@@ -427,7 +409,7 @@ func (m *Memberlist) handlePing(buf []byte, from net.Addr) {
427 427
 	if m.config.Ping != nil {
428 428
 		ack.Payload = m.config.Ping.AckPayload()
429 429
 	}
430
-	if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
430
+	if err := m.encodeAndSendMsg(from.String(), ackRespMsg, &ack); err != nil {
431 431
 		m.logger.Printf("[ERR] memberlist: Failed to send ack: %s %s", err, LogAddress(from))
432 432
 	}
433 433
 }
... ...
@@ -440,29 +422,49 @@ func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) {
440 440
 	}
441 441
 
442 442
 	// For proto versions < 2, there is no port provided. Mask old
443
-	// behavior by using the configured port
443
+	// behavior by using the configured port.
444 444
 	if m.ProtocolVersion() < 2 || ind.Port == 0 {
445 445
 		ind.Port = uint16(m.config.BindPort)
446 446
 	}
447 447
 
448
-	// Send a ping to the correct host
448
+	// Send a ping to the correct host.
449 449
 	localSeqNo := m.nextSeqNo()
450 450
 	ping := ping{SeqNo: localSeqNo, Node: ind.Node}
451
-	destAddr := &net.UDPAddr{IP: ind.Target, Port: int(ind.Port)}
452 451
 
453 452
 	// Setup a response handler to relay the ack
453
+	cancelCh := make(chan struct{})
454 454
 	respHandler := func(payload []byte, timestamp time.Time) {
455
+		// Try to prevent the nack if we've caught it in time.
456
+		close(cancelCh)
457
+
458
+		// Forward the ack back to the requestor.
455 459
 		ack := ackResp{ind.SeqNo, nil}
456
-		if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
460
+		if err := m.encodeAndSendMsg(from.String(), ackRespMsg, &ack); err != nil {
457 461
 			m.logger.Printf("[ERR] memberlist: Failed to forward ack: %s %s", err, LogAddress(from))
458 462
 		}
459 463
 	}
460 464
 	m.setAckHandler(localSeqNo, respHandler, m.config.ProbeTimeout)
461 465
 
462
-	// Send the ping
463
-	if err := m.encodeAndSendMsg(destAddr, pingMsg, &ping); err != nil {
466
+	// Send the ping.
467
+	addr := joinHostPort(net.IP(ind.Target).String(), ind.Port)
468
+	if err := m.encodeAndSendMsg(addr, pingMsg, &ping); err != nil {
464 469
 		m.logger.Printf("[ERR] memberlist: Failed to send ping: %s %s", err, LogAddress(from))
465 470
 	}
471
+
472
+	// Setup a timer to fire off a nack if no ack is seen in time.
473
+	if ind.Nack {
474
+		go func() {
475
+			select {
476
+			case <-cancelCh:
477
+				return
478
+			case <-time.After(m.config.ProbeTimeout):
479
+				nack := nackResp{ind.SeqNo}
480
+				if err := m.encodeAndSendMsg(from.String(), nackRespMsg, &nack); err != nil {
481
+					m.logger.Printf("[ERR] memberlist: Failed to send nack: %s %s", err, LogAddress(from))
482
+				}
483
+			}
484
+		}()
485
+	}
466 486
 }
467 487
 
468 488
 func (m *Memberlist) handleAck(buf []byte, from net.Addr, timestamp time.Time) {
... ...
@@ -474,6 +476,15 @@ func (m *Memberlist) handleAck(buf []byte, from net.Addr, timestamp time.Time) {
474 474
 	m.invokeAckHandler(ack, timestamp)
475 475
 }
476 476
 
477
+func (m *Memberlist) handleNack(buf []byte, from net.Addr) {
478
+	var nack nackResp
479
+	if err := decode(buf, &nack); err != nil {
480
+		m.logger.Printf("[ERR] memberlist: Failed to decode nack response: %s %s", err, LogAddress(from))
481
+		return
482
+	}
483
+	m.invokeNackHandler(nack)
484
+}
485
+
477 486
 func (m *Memberlist) handleSuspect(buf []byte, from net.Addr) {
478 487
 	var sus suspect
479 488
 	if err := decode(buf, &sus); err != nil {
... ...
@@ -530,22 +541,22 @@ func (m *Memberlist) handleCompressed(buf []byte, from net.Addr, timestamp time.
530 530
 }
531 531
 
532 532
 // encodeAndSendMsg is used to combine the encoding and sending steps
533
-func (m *Memberlist) encodeAndSendMsg(to net.Addr, msgType messageType, msg interface{}) error {
533
+func (m *Memberlist) encodeAndSendMsg(addr string, msgType messageType, msg interface{}) error {
534 534
 	out, err := encode(msgType, msg)
535 535
 	if err != nil {
536 536
 		return err
537 537
 	}
538
-	if err := m.sendMsg(to, out.Bytes()); err != nil {
538
+	if err := m.sendMsg(addr, out.Bytes()); err != nil {
539 539
 		return err
540 540
 	}
541 541
 	return nil
542 542
 }
543 543
 
544
-// sendMsg is used to send a UDP message to another host. It will opportunistically
545
-// create a compoundMsg and piggy back other broadcasts
546
-func (m *Memberlist) sendMsg(to net.Addr, msg []byte) error {
544
+// sendMsg is used to send a message via packet to another host. It will
545
+// opportunistically create a compoundMsg and piggy back other broadcasts.
546
+func (m *Memberlist) sendMsg(addr string, msg []byte) error {
547 547
 	// Check if we can piggy back any messages
548
-	bytesAvail := udpSendBuf - len(msg) - compoundHeaderOverhead
548
+	bytesAvail := m.config.UDPBufferSize - len(msg) - compoundHeaderOverhead
549 549
 	if m.config.EncryptionEnabled() {
550 550
 		bytesAvail -= encryptOverhead(m.encryptionVersion())
551 551
 	}
... ...
@@ -553,7 +564,7 @@ func (m *Memberlist) sendMsg(to net.Addr, msg []byte) error {
553 553
 
554 554
 	// Fast path if nothing to piggypack
555 555
 	if len(extra) == 0 {
556
-		return m.rawSendMsgUDP(to, msg)
556
+		return m.rawSendMsgPacket(addr, nil, msg)
557 557
 	}
558 558
 
559 559
 	// Join all the messages
... ...
@@ -565,11 +576,12 @@ func (m *Memberlist) sendMsg(to net.Addr, msg []byte) error {
565 565
 	compound := makeCompoundMessage(msgs)
566 566
 
567 567
 	// Send the message
568
-	return m.rawSendMsgUDP(to, compound.Bytes())
568
+	return m.rawSendMsgPacket(addr, nil, compound.Bytes())
569 569
 }
570 570
 
571
-// rawSendMsgUDP is used to send a UDP message to another host without modification
572
-func (m *Memberlist) rawSendMsgUDP(to net.Addr, msg []byte) error {
571
+// rawSendMsgPacket is used to send message via packet to another host without
572
+// modification, other than compression or encryption if enabled.
573
+func (m *Memberlist) rawSendMsgPacket(addr string, node *Node, msg []byte) error {
573 574
 	// Check if we have compression enabled
574 575
 	if m.config.EnableCompression {
575 576
 		buf, err := compressPayload(msg)
... ...
@@ -583,6 +595,31 @@ func (m *Memberlist) rawSendMsgUDP(to net.Addr, msg []byte) error {
583 583
 		}
584 584
 	}
585 585
 
586
+	// Try to look up the destination node
587
+	if node == nil {
588
+		toAddr, _, err := net.SplitHostPort(addr)
589
+		if err != nil {
590
+			m.logger.Printf("[ERR] memberlist: Failed to parse address %q: %v", addr, err)
591
+			return err
592
+		}
593
+		m.nodeLock.RLock()
594
+		nodeState, ok := m.nodeMap[toAddr]
595
+		m.nodeLock.RUnlock()
596
+		if ok {
597
+			node = &nodeState.Node
598
+		}
599
+	}
600
+
601
+	// Add a CRC to the end of the payload if the recipient understands
602
+	// ProtocolVersion >= 5
603
+	if node != nil && node.PMax >= 5 {
604
+		crc := crc32.ChecksumIEEE(msg)
605
+		header := make([]byte, 5, 5+len(msg))
606
+		header[0] = byte(hasCrcMsg)
607
+		binary.BigEndian.PutUint32(header[1:], crc)
608
+		msg = append(header, msg...)
609
+	}
610
+
586 611
 	// Check if we have encryption enabled
587 612
 	if m.config.EncryptionEnabled() {
588 613
 		// Encrypt the payload
... ...
@@ -597,12 +634,13 @@ func (m *Memberlist) rawSendMsgUDP(to net.Addr, msg []byte) error {
597 597
 	}
598 598
 
599 599
 	metrics.IncrCounter([]string{"memberlist", "udp", "sent"}, float32(len(msg)))
600
-	_, err := m.udpListener.WriteTo(msg, to)
600
+	_, err := m.transport.WriteTo(msg, addr)
601 601
 	return err
602 602
 }
603 603
 
604
-// rawSendMsgTCP is used to send a TCP message to another host without modification
605
-func (m *Memberlist) rawSendMsgTCP(conn net.Conn, sendBuf []byte) error {
604
+// rawSendMsgStream is used to stream a message to another host without
605
+// modification, other than applying compression and encryption if enabled.
606
+func (m *Memberlist) rawSendMsgStream(conn net.Conn, sendBuf []byte) error {
606 607
 	// Check if compresion is enabled
607 608
 	if m.config.EnableCompression {
608 609
 		compBuf, err := compressPayload(sendBuf)
... ...
@@ -635,43 +673,36 @@ func (m *Memberlist) rawSendMsgTCP(conn net.Conn, sendBuf []byte) error {
635 635
 	return nil
636 636
 }
637 637
 
638
-// sendTCPUserMsg is used to send a TCP userMsg to another host
639
-func (m *Memberlist) sendTCPUserMsg(to net.Addr, sendBuf []byte) error {
640
-	dialer := net.Dialer{Timeout: m.config.TCPTimeout}
641
-	conn, err := dialer.Dial("tcp", to.String())
638
+// sendUserMsg is used to stream a user message to another host.
639
+func (m *Memberlist) sendUserMsg(addr string, sendBuf []byte) error {
640
+	conn, err := m.transport.DialTimeout(addr, m.config.TCPTimeout)
642 641
 	if err != nil {
643 642
 		return err
644 643
 	}
645 644
 	defer conn.Close()
646 645
 
647 646
 	bufConn := bytes.NewBuffer(nil)
648
-
649 647
 	if err := bufConn.WriteByte(byte(userMsg)); err != nil {
650 648
 		return err
651 649
 	}
652 650
 
653
-	// Send our node state
654 651
 	header := userMsgHeader{UserMsgLen: len(sendBuf)}
655 652
 	hd := codec.MsgpackHandle{}
656 653
 	enc := codec.NewEncoder(bufConn, &hd)
657
-
658 654
 	if err := enc.Encode(&header); err != nil {
659 655
 		return err
660 656
 	}
661
-
662 657
 	if _, err := bufConn.Write(sendBuf); err != nil {
663 658
 		return err
664 659
 	}
665
-
666
-	return m.rawSendMsgTCP(conn, bufConn.Bytes())
660
+	return m.rawSendMsgStream(conn, bufConn.Bytes())
667 661
 }
668 662
 
669
-// sendAndReceiveState is used to initiate a push/pull over TCP with a remote node
670
-func (m *Memberlist) sendAndReceiveState(addr []byte, port uint16, join bool) ([]pushNodeState, []byte, error) {
663
+// sendAndReceiveState is used to initiate a push/pull over a stream with a
664
+// remote host.
665
+func (m *Memberlist) sendAndReceiveState(addr string, join bool) ([]pushNodeState, []byte, error) {
671 666
 	// Attempt to connect
672
-	dialer := net.Dialer{Timeout: m.config.TCPTimeout}
673
-	dest := net.TCPAddr{IP: addr, Port: int(port)}
674
-	conn, err := dialer.Dial("tcp", dest.String())
667
+	conn, err := m.transport.DialTimeout(addr, m.config.TCPTimeout)
675 668
 	if err != nil {
676 669
 		return nil, nil, err
677 670
 	}
... ...
@@ -685,7 +716,7 @@ func (m *Memberlist) sendAndReceiveState(addr []byte, port uint16, join bool) ([
685 685
 	}
686 686
 
687 687
 	conn.SetDeadline(time.Now().Add(m.config.TCPTimeout))
688
-	msgType, bufConn, dec, err := m.readTCP(conn)
688
+	msgType, bufConn, dec, err := m.readStream(conn)
689 689
 	if err != nil {
690 690
 		return nil, nil, err
691 691
 	}
... ...
@@ -701,7 +732,7 @@ func (m *Memberlist) sendAndReceiveState(addr []byte, port uint16, join bool) ([
701 701
 	return remoteNodes, userState, err
702 702
 }
703 703
 
704
-// sendLocalState is invoked to send our local state over a tcp connection
704
+// sendLocalState is invoked to send our local state over a stream connection.
705 705
 func (m *Memberlist) sendLocalState(conn net.Conn, join bool) error {
706 706
 	// Setup a deadline
707 707
 	conn.SetDeadline(time.Now().Add(m.config.TCPTimeout))
... ...
@@ -759,7 +790,7 @@ func (m *Memberlist) sendLocalState(conn net.Conn, join bool) error {
759 759
 	}
760 760
 
761 761
 	// Get the send buffer
762
-	return m.rawSendMsgTCP(conn, bufConn.Bytes())
762
+	return m.rawSendMsgStream(conn, bufConn.Bytes())
763 763
 }
764 764
 
765 765
 // encryptLocalState is used to help encrypt local state before sending
... ...
@@ -817,9 +848,9 @@ func (m *Memberlist) decryptRemoteState(bufConn io.Reader) ([]byte, error) {
817 817
 	return decryptPayload(keys, cipherBytes, dataBytes)
818 818
 }
819 819
 
820
-// readTCP is used to read the start of a TCP stream.
821
-// it decrypts and decompresses the stream if necessary
822
-func (m *Memberlist) readTCP(conn net.Conn) (messageType, io.Reader, *codec.Decoder, error) {
820
+// readStream is used to read from a stream connection, decrypting and
821
+// decompressing the stream if necessary.
822
+func (m *Memberlist) readStream(conn net.Conn) (messageType, io.Reader, *codec.Decoder, error) {
823 823
 	// Created a buffered reader
824 824
 	var bufConn io.Reader = bufio.NewReader(conn)
825 825
 
... ...
@@ -960,7 +991,7 @@ func (m *Memberlist) mergeRemoteState(join bool, remoteNodes []pushNodeState, us
960 960
 	return nil
961 961
 }
962 962
 
963
-// readUserMsg is used to decode a userMsg from a TCP stream
963
+// readUserMsg is used to decode a userMsg from a stream.
964 964
 func (m *Memberlist) readUserMsg(bufConn io.Reader, dec *codec.Decoder) error {
965 965
 	// Read the user message header
966 966
 	var header userMsgHeader
... ...
@@ -991,13 +1022,12 @@ func (m *Memberlist) readUserMsg(bufConn io.Reader, dec *codec.Decoder) error {
991 991
 	return nil
992 992
 }
993 993
 
994
-// sendPingAndWaitForAck makes a TCP connection to the given address, sends
994
+// sendPingAndWaitForAck makes a stream connection to the given address, sends
995 995
 // a ping, and waits for an ack. All of this is done as a series of blocking
996 996
 // operations, given the deadline. The bool return parameter is true if we
997 997
 // we able to round trip a ping to the other node.
998
-func (m *Memberlist) sendPingAndWaitForAck(destAddr net.Addr, ping ping, deadline time.Time) (bool, error) {
999
-	dialer := net.Dialer{Deadline: deadline}
1000
-	conn, err := dialer.Dial("tcp", destAddr.String())
998
+func (m *Memberlist) sendPingAndWaitForAck(addr string, ping ping, deadline time.Time) (bool, error) {
999
+	conn, err := m.transport.DialTimeout(addr, m.config.TCPTimeout)
1001 1000
 	if err != nil {
1002 1001
 		// If the node is actually dead we expect this to fail, so we
1003 1002
 		// shouldn't spam the logs with it. After this point, errors
... ...
@@ -1013,17 +1043,17 @@ func (m *Memberlist) sendPingAndWaitForAck(destAddr net.Addr, ping ping, deadlin
1013 1013
 		return false, err
1014 1014
 	}
1015 1015
 
1016
-	if err = m.rawSendMsgTCP(conn, out.Bytes()); err != nil {
1016
+	if err = m.rawSendMsgStream(conn, out.Bytes()); err != nil {
1017 1017
 		return false, err
1018 1018
 	}
1019 1019
 
1020
-	msgType, _, dec, err := m.readTCP(conn)
1020
+	msgType, _, dec, err := m.readStream(conn)
1021 1021
 	if err != nil {
1022 1022
 		return false, err
1023 1023
 	}
1024 1024
 
1025 1025
 	if msgType != ackRespMsg {
1026
-		return false, fmt.Errorf("Unexpected msgType (%d) from TCP ping %s", msgType, LogConn(conn))
1026
+		return false, fmt.Errorf("Unexpected msgType (%d) from ping %s", msgType, LogConn(conn))
1027 1027
 	}
1028 1028
 
1029 1029
 	var ack ackResp
... ...
@@ -1032,7 +1062,7 @@ func (m *Memberlist) sendPingAndWaitForAck(destAddr net.Addr, ping ping, deadlin
1032 1032
 	}
1033 1033
 
1034 1034
 	if ack.SeqNo != ping.SeqNo {
1035
-		return false, fmt.Errorf("Sequence number from ack (%d) doesn't match ping (%d) from TCP ping %s", ack.SeqNo, ping.SeqNo, LogConn(conn))
1035
+		return false, fmt.Errorf("Sequence number from ack (%d) doesn't match ping (%d)", ack.SeqNo, ping.SeqNo, LogConn(conn))
1036 1036
 	}
1037 1037
 
1038 1038
 	return true, nil
1039 1039
new file mode 100644
... ...
@@ -0,0 +1,289 @@
0
+package memberlist
1
+
2
+import (
3
+	"fmt"
4
+	"log"
5
+	"net"
6
+	"sync"
7
+	"sync/atomic"
8
+	"time"
9
+
10
+	"github.com/armon/go-metrics"
11
+	sockaddr "github.com/hashicorp/go-sockaddr"
12
+)
13
+
14
+const (
15
+	// udpPacketBufSize is used to buffer incoming packets during read
16
+	// operations.
17
+	udpPacketBufSize = 65536
18
+
19
+	// udpRecvBufSize is a large buffer size that we attempt to set UDP
20
+	// sockets to in order to handle a large volume of messages.
21
+	udpRecvBufSize = 2 * 1024 * 1024
22
+)
23
+
24
+// NetTransportConfig is used to configure a net transport.
25
+type NetTransportConfig struct {
26
+	// BindAddrs is a list of addresses to bind to for both TCP and UDP
27
+	// communications.
28
+	BindAddrs []string
29
+
30
+	// BindPort is the port to listen on, for each address above.
31
+	BindPort int
32
+
33
+	// Logger is a logger for operator messages.
34
+	Logger *log.Logger
35
+}
36
+
37
+// NetTransport is a Transport implementation that uses connectionless UDP for
38
+// packet operations, and ad-hoc TCP connections for stream operations.
39
+type NetTransport struct {
40
+	config       *NetTransportConfig
41
+	packetCh     chan *Packet
42
+	streamCh     chan net.Conn
43
+	logger       *log.Logger
44
+	wg           sync.WaitGroup
45
+	tcpListeners []*net.TCPListener
46
+	udpListeners []*net.UDPConn
47
+	shutdown     int32
48
+}
49
+
50
+// NewNetTransport returns a net transport with the given configuration. On
51
+// success all the network listeners will be created and listening.
52
+func NewNetTransport(config *NetTransportConfig) (*NetTransport, error) {
53
+	// If we reject the empty list outright we can assume that there's at
54
+	// least one listener of each type later during operation.
55
+	if len(config.BindAddrs) == 0 {
56
+		return nil, fmt.Errorf("At least one bind address is required")
57
+	}
58
+
59
+	// Build out the new transport.
60
+	var ok bool
61
+	t := NetTransport{
62
+		config:   config,
63
+		packetCh: make(chan *Packet),
64
+		streamCh: make(chan net.Conn),
65
+		logger:   config.Logger,
66
+	}
67
+
68
+	// Clean up listeners if there's an error.
69
+	defer func() {
70
+		if !ok {
71
+			t.Shutdown()
72
+		}
73
+	}()
74
+
75
+	// Build all the TCP and UDP listeners.
76
+	port := config.BindPort
77
+	for _, addr := range config.BindAddrs {
78
+		ip := net.ParseIP(addr)
79
+
80
+		tcpAddr := &net.TCPAddr{IP: ip, Port: port}
81
+		tcpLn, err := net.ListenTCP("tcp", tcpAddr)
82
+		if err != nil {
83
+			return nil, fmt.Errorf("Failed to start TCP listener on %q port %d: %v", addr, port, err)
84
+		}
85
+		t.tcpListeners = append(t.tcpListeners, tcpLn)
86
+
87
+		// If the config port given was zero, use the first TCP listener
88
+		// to pick an available port and then apply that to everything
89
+		// else.
90
+		if port == 0 {
91
+			port = tcpLn.Addr().(*net.TCPAddr).Port
92
+		}
93
+
94
+		udpAddr := &net.UDPAddr{IP: ip, Port: port}
95
+		udpLn, err := net.ListenUDP("udp", udpAddr)
96
+		if err != nil {
97
+			return nil, fmt.Errorf("Failed to start UDP listener on %q port %d: %v", addr, port, err)
98
+		}
99
+		if err := setUDPRecvBuf(udpLn); err != nil {
100
+			return nil, fmt.Errorf("Failed to resize UDP buffer: %v", err)
101
+		}
102
+		t.udpListeners = append(t.udpListeners, udpLn)
103
+	}
104
+
105
+	// Fire them up now that we've been able to create them all.
106
+	for i := 0; i < len(config.BindAddrs); i++ {
107
+		t.wg.Add(2)
108
+		go t.tcpListen(t.tcpListeners[i])
109
+		go t.udpListen(t.udpListeners[i])
110
+	}
111
+
112
+	ok = true
113
+	return &t, nil
114
+}
115
+
116
+// GetAutoBindPort returns the bind port that was automatically given by the
117
+// kernel, if a bind port of 0 was given.
118
+func (t *NetTransport) GetAutoBindPort() int {
119
+	// We made sure there's at least one TCP listener, and that one's
120
+	// port was applied to all the others for the dynamic bind case.
121
+	return t.tcpListeners[0].Addr().(*net.TCPAddr).Port
122
+}
123
+
124
+// See Transport.
125
+func (t *NetTransport) FinalAdvertiseAddr(ip string, port int) (net.IP, int, error) {
126
+	var advertiseAddr net.IP
127
+	var advertisePort int
128
+	if ip != "" {
129
+		// If they've supplied an address, use that.
130
+		advertiseAddr = net.ParseIP(ip)
131
+		if advertiseAddr == nil {
132
+			return nil, 0, fmt.Errorf("Failed to parse advertise address %q", ip)
133
+		}
134
+
135
+		// Ensure IPv4 conversion if necessary.
136
+		if ip4 := advertiseAddr.To4(); ip4 != nil {
137
+			advertiseAddr = ip4
138
+		}
139
+		advertisePort = port
140
+	} else {
141
+		if t.config.BindAddrs[0] == "0.0.0.0" {
142
+			// Otherwise, if we're not bound to a specific IP, let's
143
+			// use a suitable private IP address.
144
+			var err error
145
+			ip, err = sockaddr.GetPrivateIP()
146
+			if err != nil {
147
+				return nil, 0, fmt.Errorf("Failed to get interface addresses: %v", err)
148
+			}
149
+			if ip == "" {
150
+				return nil, 0, fmt.Errorf("No private IP address found, and explicit IP not provided")
151
+			}
152
+
153
+			advertiseAddr = net.ParseIP(ip)
154
+			if advertiseAddr == nil {
155
+				return nil, 0, fmt.Errorf("Failed to parse advertise address: %q", ip)
156
+			}
157
+		} else {
158
+			// Use the IP that we're bound to, based on the first
159
+			// TCP listener, which we already ensure is there.
160
+			advertiseAddr = t.tcpListeners[0].Addr().(*net.TCPAddr).IP
161
+		}
162
+
163
+		// Use the port we are bound to.
164
+		advertisePort = t.GetAutoBindPort()
165
+	}
166
+
167
+	return advertiseAddr, advertisePort, nil
168
+}
169
+
170
+// See Transport.
171
+func (t *NetTransport) WriteTo(b []byte, addr string) (time.Time, error) {
172
+	udpAddr, err := net.ResolveUDPAddr("udp", addr)
173
+	if err != nil {
174
+		return time.Time{}, err
175
+	}
176
+
177
+	// We made sure there's at least one UDP listener, so just use the
178
+	// packet sending interface on the first one. Take the time after the
179
+	// write call comes back, which will underestimate the time a little,
180
+	// but help account for any delays before the write occurs.
181
+	_, err = t.udpListeners[0].WriteTo(b, udpAddr)
182
+	return time.Now(), err
183
+}
184
+
185
+// See Transport.
186
+func (t *NetTransport) PacketCh() <-chan *Packet {
187
+	return t.packetCh
188
+}
189
+
190
+// See Transport.
191
+func (t *NetTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
192
+	dialer := net.Dialer{Timeout: timeout}
193
+	return dialer.Dial("tcp", addr)
194
+}
195
+
196
+// See Transport.
197
+func (t *NetTransport) StreamCh() <-chan net.Conn {
198
+	return t.streamCh
199
+}
200
+
201
+// See Transport.
202
+func (t *NetTransport) Shutdown() error {
203
+	// This will avoid log spam about errors when we shut down.
204
+	atomic.StoreInt32(&t.shutdown, 1)
205
+
206
+	// Rip through all the connections and shut them down.
207
+	for _, conn := range t.tcpListeners {
208
+		conn.Close()
209
+	}
210
+	for _, conn := range t.udpListeners {
211
+		conn.Close()
212
+	}
213
+
214
+	// Block until all the listener threads have died.
215
+	t.wg.Wait()
216
+	return nil
217
+}
218
+
219
+// tcpListen is a long running goroutine that accepts incoming TCP connections
220
+// and hands them off to the stream channel.
221
+func (t *NetTransport) tcpListen(tcpLn *net.TCPListener) {
222
+	defer t.wg.Done()
223
+	for {
224
+		conn, err := tcpLn.AcceptTCP()
225
+		if err != nil {
226
+			if s := atomic.LoadInt32(&t.shutdown); s == 1 {
227
+				break
228
+			}
229
+
230
+			t.logger.Printf("[ERR] memberlist: Error accepting TCP connection: %v", err)
231
+			continue
232
+		}
233
+
234
+		t.streamCh <- conn
235
+	}
236
+}
237
+
238
+// udpListen is a long running goroutine that accepts incoming UDP packets and
239
+// hands them off to the packet channel.
240
+func (t *NetTransport) udpListen(udpLn *net.UDPConn) {
241
+	defer t.wg.Done()
242
+	for {
243
+		// Do a blocking read into a fresh buffer. Grab a time stamp as
244
+		// close as possible to the I/O.
245
+		buf := make([]byte, udpPacketBufSize)
246
+		n, addr, err := udpLn.ReadFrom(buf)
247
+		ts := time.Now()
248
+		if err != nil {
249
+			if s := atomic.LoadInt32(&t.shutdown); s == 1 {
250
+				break
251
+			}
252
+
253
+			t.logger.Printf("[ERR] memberlist: Error reading UDP packet: %v", err)
254
+			continue
255
+		}
256
+
257
+		// Check the length - it needs to have at least one byte to be a
258
+		// proper message.
259
+		if n < 1 {
260
+			t.logger.Printf("[ERR] memberlist: UDP packet too short (%d bytes) %s",
261
+				len(buf), LogAddress(addr))
262
+			continue
263
+		}
264
+
265
+		// Ingest the packet.
266
+		metrics.IncrCounter([]string{"memberlist", "udp", "received"}, float32(n))
267
+		t.packetCh <- &Packet{
268
+			Buf:       buf[:n],
269
+			From:      addr,
270
+			Timestamp: ts,
271
+		}
272
+	}
273
+}
274
+
275
+// setUDPRecvBuf is used to resize the UDP receive window. The function
276
+// attempts to set the read buffer to `udpRecvBuf` but backs off until
277
+// the read buffer can be set.
278
+func setUDPRecvBuf(c *net.UDPConn) error {
279
+	size := udpRecvBufSize
280
+	var err error
281
+	for size > 0 {
282
+		if err = c.SetReadBuffer(size); err == nil {
283
+			return nil
284
+		}
285
+		size = size / 2
286
+	}
287
+	return err
288
+}
... ...
@@ -34,6 +34,12 @@ type Node struct {
34 34
 	DCur uint8  // Current version delegate is speaking
35 35
 }
36 36
 
37
+// Address returns the host:port form of a node's address, suitable for use
38
+// with a transport.
39
+func (n *Node) Address() string {
40
+	return joinHostPort(n.Addr.String(), n.Port)
41
+}
42
+
37 43
 // NodeState is used to manage our state view of another node
38 44
 type nodeState struct {
39 45
 	Node
... ...
@@ -42,10 +48,17 @@ type nodeState struct {
42 42
 	StateChange time.Time     // Time last state change happened
43 43
 }
44 44
 
45
-// ackHandler is used to register handlers for incoming acks
45
+// Address returns the host:port form of a node's address, suitable for use
46
+// with a transport.
47
+func (n *nodeState) Address() string {
48
+	return n.Node.Address()
49
+}
50
+
51
+// ackHandler is used to register handlers for incoming acks and nacks.
46 52
 type ackHandler struct {
47
-	handler func([]byte, time.Time)
48
-	timer   *time.Timer
53
+	ackFn  func([]byte, time.Time)
54
+	nackFn func()
55
+	timer  *time.Timer
49 56
 }
50 57
 
51 58
 // NoPingResponseError is used to indicate a 'ping' packet was
... ...
@@ -148,7 +161,7 @@ func (m *Memberlist) pushPullTrigger(stop <-chan struct{}) {
148 148
 	}
149 149
 }
150 150
 
151
-// Deschedule is used to stop the background maintenence. This is safe
151
+// Deschedule is used to stop the background maintenance. This is safe
152 152
 // to call multiple times.
153 153
 func (m *Memberlist) deschedule() {
154 154
 	m.tickerLock.Lock()
... ...
@@ -219,17 +232,51 @@ START:
219 219
 func (m *Memberlist) probeNode(node *nodeState) {
220 220
 	defer metrics.MeasureSince([]string{"memberlist", "probeNode"}, time.Now())
221 221
 
222
+	// We use our health awareness to scale the overall probe interval, so we
223
+	// slow down if we detect problems. The ticker that calls us can handle
224
+	// us running over the base interval, and will skip missed ticks.
225
+	probeInterval := m.awareness.ScaleTimeout(m.config.ProbeInterval)
226
+	if probeInterval > m.config.ProbeInterval {
227
+		metrics.IncrCounter([]string{"memberlist", "degraded", "probe"}, 1)
228
+	}
229
+
222 230
 	// Prepare a ping message and setup an ack handler.
223 231
 	ping := ping{SeqNo: m.nextSeqNo(), Node: node.Name}
224 232
 	ackCh := make(chan ackMessage, m.config.IndirectChecks+1)
225
-	m.setAckChannel(ping.SeqNo, ackCh, m.config.ProbeInterval)
233
+	nackCh := make(chan struct{}, m.config.IndirectChecks+1)
234
+	m.setProbeChannels(ping.SeqNo, ackCh, nackCh, probeInterval)
235
+
236
+	// Send a ping to the node. If this node looks like it's suspect or dead,
237
+	// also tack on a suspect message so that it has a chance to refute as
238
+	// soon as possible.
239
+	deadline := time.Now().Add(probeInterval)
240
+	addr := node.Address()
241
+	if node.State == stateAlive {
242
+		if err := m.encodeAndSendMsg(addr, pingMsg, &ping); err != nil {
243
+			m.logger.Printf("[ERR] memberlist: Failed to send ping: %s", err)
244
+			return
245
+		}
246
+	} else {
247
+		var msgs [][]byte
248
+		if buf, err := encode(pingMsg, &ping); err != nil {
249
+			m.logger.Printf("[ERR] memberlist: Failed to encode ping message: %s", err)
250
+			return
251
+		} else {
252
+			msgs = append(msgs, buf.Bytes())
253
+		}
254
+		s := suspect{Incarnation: node.Incarnation, Node: node.Name, From: m.config.Name}
255
+		if buf, err := encode(suspectMsg, &s); err != nil {
256
+			m.logger.Printf("[ERR] memberlist: Failed to encode suspect message: %s", err)
257
+			return
258
+		} else {
259
+			msgs = append(msgs, buf.Bytes())
260
+		}
226 261
 
227
-	// Send a ping to the node.
228
-	deadline := time.Now().Add(m.config.ProbeInterval)
229
-	destAddr := &net.UDPAddr{IP: node.Addr, Port: int(node.Port)}
230
-	if err := m.encodeAndSendMsg(destAddr, pingMsg, &ping); err != nil {
231
-		m.logger.Printf("[ERR] memberlist: Failed to send ping: %s", err)
232
-		return
262
+		compound := makeCompoundMessage(msgs)
263
+		if err := m.rawSendMsgPacket(addr, &node.Node, compound.Bytes()); err != nil {
264
+			m.logger.Printf("[ERR] memberlist: Failed to send compound ping and suspect message to %s: %s", addr, err)
265
+			return
266
+		}
233 267
 	}
234 268
 
235 269
 	// Mark the sent time here, which should be after any pre-processing and
... ...
@@ -237,6 +284,16 @@ func (m *Memberlist) probeNode(node *nodeState) {
237 237
 	// but it's the best we can do.
238 238
 	sent := time.Now()
239 239
 
240
+	// Arrange for our self-awareness to get updated. At this point we've
241
+	// sent the ping, so any return statement means the probe succeeded
242
+	// which will improve our health until we get to the failure scenarios
243
+	// at the end of this function, which will alter this delta variable
244
+	// accordingly.
245
+	awarenessDelta := -1
246
+	defer func() {
247
+		m.awareness.ApplyDelta(awarenessDelta)
248
+	}()
249
+
240 250
 	// Wait for response or round-trip-time.
241 251
 	select {
242 252
 	case v := <-ackCh:
... ...
@@ -254,20 +311,35 @@ func (m *Memberlist) probeNode(node *nodeState) {
254 254
 			ackCh <- v
255 255
 		}
256 256
 	case <-time.After(m.config.ProbeTimeout):
257
-		m.logger.Printf("[DEBUG] memberlist: Failed UDP ping: %v (timeout reached)", node.Name)
257
+		// Note that we don't scale this timeout based on awareness and
258
+		// the health score. That's because we don't really expect waiting
259
+		// longer to help get UDP through. Since health does extend the
260
+		// probe interval it will give the TCP fallback more time, which
261
+		// is more active in dealing with lost packets, and it gives more
262
+		// time to wait for indirect acks/nacks.
263
+		m.logger.Printf("[DEBUG] memberlist: Failed ping: %v (timeout reached)", node.Name)
258 264
 	}
259 265
 
260 266
 	// Get some random live nodes.
261 267
 	m.nodeLock.RLock()
262
-	excludes := []string{m.config.Name, node.Name}
263
-	kNodes := kRandomNodes(m.config.IndirectChecks, excludes, m.nodes)
268
+	kNodes := kRandomNodes(m.config.IndirectChecks, m.nodes, func(n *nodeState) bool {
269
+		return n.Name == m.config.Name ||
270
+			n.Name == node.Name ||
271
+			n.State != stateAlive
272
+	})
264 273
 	m.nodeLock.RUnlock()
265 274
 
266 275
 	// Attempt an indirect ping.
276
+	expectedNacks := 0
267 277
 	ind := indirectPingReq{SeqNo: ping.SeqNo, Target: node.Addr, Port: node.Port, Node: node.Name}
268 278
 	for _, peer := range kNodes {
269
-		destAddr := &net.UDPAddr{IP: peer.Addr, Port: int(peer.Port)}
270
-		if err := m.encodeAndSendMsg(destAddr, indirectPingMsg, &ind); err != nil {
279
+		// We only expect nack to be sent from peers who understand
280
+		// version 4 of the protocol.
281
+		if ind.Nack = peer.PMax >= 4; ind.Nack {
282
+			expectedNacks++
283
+		}
284
+
285
+		if err := m.encodeAndSendMsg(peer.Address(), indirectPingMsg, &ind); err != nil {
271 286
 			m.logger.Printf("[ERR] memberlist: Failed to send indirect ping: %s", err)
272 287
 		}
273 288
 	}
... ...
@@ -284,12 +356,11 @@ func (m *Memberlist) probeNode(node *nodeState) {
284 284
 	// config option to turn this off if desired.
285 285
 	fallbackCh := make(chan bool, 1)
286 286
 	if (!m.config.DisableTcpPings) && (node.PMax >= 3) {
287
-		destAddr := &net.TCPAddr{IP: node.Addr, Port: int(node.Port)}
288 287
 		go func() {
289 288
 			defer close(fallbackCh)
290
-			didContact, err := m.sendPingAndWaitForAck(destAddr, ping, deadline)
289
+			didContact, err := m.sendPingAndWaitForAck(node.Address(), ping, deadline)
291 290
 			if err != nil {
292
-				m.logger.Printf("[ERR] memberlist: Failed TCP fallback ping: %s", err)
291
+				m.logger.Printf("[ERR] memberlist: Failed fallback ping: %s", err)
293 292
 			} else {
294 293
 				fallbackCh <- didContact
295 294
 			}
... ...
@@ -314,12 +385,28 @@ func (m *Memberlist) probeNode(node *nodeState) {
314 314
 	// any additional time here.
315 315
 	for didContact := range fallbackCh {
316 316
 		if didContact {
317
-			m.logger.Printf("[WARN] memberlist: Was able to reach %s via TCP but not UDP, network may be misconfigured and not allowing bidirectional UDP", node.Name)
317
+			m.logger.Printf("[WARN] memberlist: Was able to connect to %s but other probes failed, network may be misconfigured", node.Name)
318 318
 			return
319 319
 		}
320 320
 	}
321 321
 
322
-	// No acks received from target, suspect
322
+	// Update our self-awareness based on the results of this failed probe.
323
+	// If we don't have peers who will send nacks then we penalize for any
324
+	// failed probe as a simple health metric. If we do have peers to nack
325
+	// verify, then we can use that as a more sophisticated measure of self-
326
+	// health because we assume them to be working, and they can help us
327
+	// decide if the probed node was really dead or if it was something wrong
328
+	// with ourselves.
329
+	awarenessDelta = 0
330
+	if expectedNacks > 0 {
331
+		if nackCount := len(nackCh); nackCount < expectedNacks {
332
+			awarenessDelta += (expectedNacks - nackCount)
333
+		}
334
+	} else {
335
+		awarenessDelta += 1
336
+	}
337
+
338
+	// No acks received from target, suspect it as failed.
323 339
 	m.logger.Printf("[INFO] memberlist: Suspect %s has failed, no acks received", node.Name)
324 340
 	s := suspect{Incarnation: node.Incarnation, Node: node.Name, From: m.config.Name}
325 341
 	m.suspectNode(&s)
... ...
@@ -330,10 +417,10 @@ func (m *Memberlist) Ping(node string, addr net.Addr) (time.Duration, error) {
330 330
 	// Prepare a ping message and setup an ack handler.
331 331
 	ping := ping{SeqNo: m.nextSeqNo(), Node: node}
332 332
 	ackCh := make(chan ackMessage, m.config.IndirectChecks+1)
333
-	m.setAckChannel(ping.SeqNo, ackCh, m.config.ProbeInterval)
333
+	m.setProbeChannels(ping.SeqNo, ackCh, nil, m.config.ProbeInterval)
334 334
 
335 335
 	// Send a ping to the node.
336
-	if err := m.encodeAndSendMsg(addr, pingMsg, &ping); err != nil {
336
+	if err := m.encodeAndSendMsg(addr.String(), pingMsg, &ping); err != nil {
337 337
 		return 0, err
338 338
 	}
339 339
 
... ...
@@ -362,8 +449,8 @@ func (m *Memberlist) resetNodes() {
362 362
 	m.nodeLock.Lock()
363 363
 	defer m.nodeLock.Unlock()
364 364
 
365
-	// Move the dead nodes
366
-	deadIdx := moveDeadNodes(m.nodes)
365
+	// Move dead nodes, but respect gossip to the dead interval
366
+	deadIdx := moveDeadNodes(m.nodes, m.config.GossipToTheDeadTime)
367 367
 
368 368
 	// Deregister the dead nodes
369 369
 	for i := deadIdx; i < len(m.nodes); i++ {
... ...
@@ -386,14 +473,28 @@ func (m *Memberlist) resetNodes() {
386 386
 func (m *Memberlist) gossip() {
387 387
 	defer metrics.MeasureSince([]string{"memberlist", "gossip"}, time.Now())
388 388
 
389
-	// Get some random live nodes
389
+	// Get some random live, suspect, or recently dead nodes
390 390
 	m.nodeLock.RLock()
391
-	excludes := []string{m.config.Name}
392
-	kNodes := kRandomNodes(m.config.GossipNodes, excludes, m.nodes)
391
+	kNodes := kRandomNodes(m.config.GossipNodes, m.nodes, func(n *nodeState) bool {
392
+		if n.Name == m.config.Name {
393
+			return true
394
+		}
395
+
396
+		switch n.State {
397
+		case stateAlive, stateSuspect:
398
+			return false
399
+
400
+		case stateDead:
401
+			return time.Since(n.StateChange) > m.config.GossipToTheDeadTime
402
+
403
+		default:
404
+			return true
405
+		}
406
+	})
393 407
 	m.nodeLock.RUnlock()
394 408
 
395 409
 	// Compute the bytes available
396
-	bytesAvail := udpSendBuf - compoundHeaderOverhead
410
+	bytesAvail := m.config.UDPBufferSize - compoundHeaderOverhead
397 411
 	if m.config.EncryptionEnabled() {
398 412
 		bytesAvail -= encryptOverhead(m.encryptionVersion())
399 413
 	}
... ...
@@ -405,13 +506,18 @@ func (m *Memberlist) gossip() {
405 405
 			return
406 406
 		}
407 407
 
408
-		// Create a compound message
409
-		compound := makeCompoundMessage(msgs)
410
-
411
-		// Send the compound message
412
-		destAddr := &net.UDPAddr{IP: node.Addr, Port: int(node.Port)}
413
-		if err := m.rawSendMsgUDP(destAddr, compound.Bytes()); err != nil {
414
-			m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", destAddr, err)
408
+		addr := node.Address()
409
+		if len(msgs) == 1 {
410
+			// Send single message as is
411
+			if err := m.rawSendMsgPacket(addr, &node.Node, msgs[0]); err != nil {
412
+				m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err)
413
+			}
414
+		} else {
415
+			// Otherwise create and send a compound message
416
+			compound := makeCompoundMessage(msgs)
417
+			if err := m.rawSendMsgPacket(addr, &node.Node, compound.Bytes()); err != nil {
418
+				m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err)
419
+			}
415 420
 		}
416 421
 	}
417 422
 }
... ...
@@ -423,8 +529,10 @@ func (m *Memberlist) gossip() {
423 423
 func (m *Memberlist) pushPull() {
424 424
 	// Get a random live node
425 425
 	m.nodeLock.RLock()
426
-	excludes := []string{m.config.Name}
427
-	nodes := kRandomNodes(1, excludes, m.nodes)
426
+	nodes := kRandomNodes(1, m.nodes, func(n *nodeState) bool {
427
+		return n.Name == m.config.Name ||
428
+			n.State != stateAlive
429
+	})
428 430
 	m.nodeLock.RUnlock()
429 431
 
430 432
 	// If no nodes, bail
... ...
@@ -434,17 +542,17 @@ func (m *Memberlist) pushPull() {
434 434
 	node := nodes[0]
435 435
 
436 436
 	// Attempt a push pull
437
-	if err := m.pushPullNode(node.Addr, node.Port, false); err != nil {
437
+	if err := m.pushPullNode(node.Address(), false); err != nil {
438 438
 		m.logger.Printf("[ERR] memberlist: Push/Pull with %s failed: %s", node.Name, err)
439 439
 	}
440 440
 }
441 441
 
442 442
 // pushPullNode does a complete state exchange with a specific node.
443
-func (m *Memberlist) pushPullNode(addr []byte, port uint16, join bool) error {
443
+func (m *Memberlist) pushPullNode(addr string, join bool) error {
444 444
 	defer metrics.MeasureSince([]string{"memberlist", "pushPullNode"}, time.Now())
445 445
 
446 446
 	// Attempt to send and receive with the node
447
-	remote, userState, err := m.sendAndReceiveState(addr, port, join)
447
+	remote, userState, err := m.sendAndReceiveState(addr, join)
448 448
 	if err != nil {
449 449
 		return err
450 450
 	}
... ...
@@ -584,6 +692,11 @@ func (m *Memberlist) nextIncarnation() uint32 {
584 584
 	return atomic.AddUint32(&m.incarnation, 1)
585 585
 }
586 586
 
587
+// skipIncarnation adds the positive offset to the incarnation number.
588
+func (m *Memberlist) skipIncarnation(offset uint32) uint32 {
589
+	return atomic.AddUint32(&m.incarnation, offset)
590
+}
591
+
587 592
 // estNumNodes is used to get the current estimate of the number of nodes
588 593
 func (m *Memberlist) estNumNodes() int {
589 594
 	return int(atomic.LoadUint32(&m.numNodes))
... ...
@@ -595,19 +708,27 @@ type ackMessage struct {
595 595
 	Timestamp time.Time
596 596
 }
597 597
 
598
-// setAckChannel is used to attach a channel to receive a message when an ack with a given
599
-// sequence number is received. The `complete` field of the message will be false on timeout
600
-func (m *Memberlist) setAckChannel(seqNo uint32, ch chan ackMessage, timeout time.Duration) {
601
-	// Create a handler function
602
-	handler := func(payload []byte, timestamp time.Time) {
598
+// setProbeChannels is used to attach the ackCh to receive a message when an ack
599
+// with a given sequence number is received. The `complete` field of the message
600
+// will be false on timeout. Any nack messages will cause an empty struct to be
601
+// passed to the nackCh, which can be nil if not needed.
602
+func (m *Memberlist) setProbeChannels(seqNo uint32, ackCh chan ackMessage, nackCh chan struct{}, timeout time.Duration) {
603
+	// Create handler functions for acks and nacks
604
+	ackFn := func(payload []byte, timestamp time.Time) {
605
+		select {
606
+		case ackCh <- ackMessage{true, payload, timestamp}:
607
+		default:
608
+		}
609
+	}
610
+	nackFn := func() {
603 611
 		select {
604
-		case ch <- ackMessage{true, payload, timestamp}:
612
+		case nackCh <- struct{}{}:
605 613
 		default:
606 614
 		}
607 615
 	}
608 616
 
609
-	// Add the handler
610
-	ah := &ackHandler{handler, nil}
617
+	// Add the handlers
618
+	ah := &ackHandler{ackFn, nackFn, nil}
611 619
 	m.ackLock.Lock()
612 620
 	m.ackHandlers[seqNo] = ah
613 621
 	m.ackLock.Unlock()
... ...
@@ -618,18 +739,19 @@ func (m *Memberlist) setAckChannel(seqNo uint32, ch chan ackMessage, timeout tim
618 618
 		delete(m.ackHandlers, seqNo)
619 619
 		m.ackLock.Unlock()
620 620
 		select {
621
-		case ch <- ackMessage{false, nil, time.Now()}:
621
+		case ackCh <- ackMessage{false, nil, time.Now()}:
622 622
 		default:
623 623
 		}
624 624
 	})
625 625
 }
626 626
 
627
-// setAckHandler is used to attach a handler to be invoked when an
628
-// ack with a given sequence number is received. If a timeout is reached,
629
-// the handler is deleted
630
-func (m *Memberlist) setAckHandler(seqNo uint32, handler func([]byte, time.Time), timeout time.Duration) {
627
+// setAckHandler is used to attach a handler to be invoked when an ack with a
628
+// given sequence number is received. If a timeout is reached, the handler is
629
+// deleted. This is used for indirect pings so does not configure a function
630
+// for nacks.
631
+func (m *Memberlist) setAckHandler(seqNo uint32, ackFn func([]byte, time.Time), timeout time.Duration) {
631 632
 	// Add the handler
632
-	ah := &ackHandler{handler, nil}
633
+	ah := &ackHandler{ackFn, nil, nil}
633 634
 	m.ackLock.Lock()
634 635
 	m.ackHandlers[seqNo] = ah
635 636
 	m.ackLock.Unlock()
... ...
@@ -642,7 +764,7 @@ func (m *Memberlist) setAckHandler(seqNo uint32, handler func([]byte, time.Time)
642 642
 	})
643 643
 }
644 644
 
645
-// Invokes an Ack handler if any is associated, and reaps the handler immediately
645
+// Invokes an ack handler if any is associated, and reaps the handler immediately
646 646
 func (m *Memberlist) invokeAckHandler(ack ackResp, timestamp time.Time) {
647 647
 	m.ackLock.Lock()
648 648
 	ah, ok := m.ackHandlers[ack.SeqNo]
... ...
@@ -652,7 +774,49 @@ func (m *Memberlist) invokeAckHandler(ack ackResp, timestamp time.Time) {
652 652
 		return
653 653
 	}
654 654
 	ah.timer.Stop()
655
-	ah.handler(ack.Payload, timestamp)
655
+	ah.ackFn(ack.Payload, timestamp)
656
+}
657
+
658
+// Invokes nack handler if any is associated.
659
+func (m *Memberlist) invokeNackHandler(nack nackResp) {
660
+	m.ackLock.Lock()
661
+	ah, ok := m.ackHandlers[nack.SeqNo]
662
+	m.ackLock.Unlock()
663
+	if !ok || ah.nackFn == nil {
664
+		return
665
+	}
666
+	ah.nackFn()
667
+}
668
+
669
+// refute gossips an alive message in response to incoming information that we
670
+// are suspect or dead. It will make sure the incarnation number beats the given
671
+// accusedInc value, or you can supply 0 to just get the next incarnation number.
672
+// This alters the node state that's passed in so this MUST be called while the
673
+// nodeLock is held.
674
+func (m *Memberlist) refute(me *nodeState, accusedInc uint32) {
675
+	// Make sure the incarnation number beats the accusation.
676
+	inc := m.nextIncarnation()
677
+	if accusedInc >= inc {
678
+		inc = m.skipIncarnation(accusedInc - inc + 1)
679
+	}
680
+	me.Incarnation = inc
681
+
682
+	// Decrease our health because we are being asked to refute a problem.
683
+	m.awareness.ApplyDelta(1)
684
+
685
+	// Format and broadcast an alive message.
686
+	a := alive{
687
+		Incarnation: inc,
688
+		Node:        me.Name,
689
+		Addr:        me.Addr,
690
+		Port:        me.Port,
691
+		Meta:        me.Meta,
692
+		Vsn: []uint8{
693
+			me.PMin, me.PMax, me.PCur,
694
+			me.DMin, me.DMax, me.DCur,
695
+		},
696
+	}
697
+	m.encodeAndBroadcast(me.Addr.String(), aliveMsg, a)
656 698
 }
657 699
 
658 700
 // aliveNode is invoked by the network layer when we get a message about a
... ...
@@ -754,6 +918,9 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) {
754 754
 		return
755 755
 	}
756 756
 
757
+	// Clear out any suspicion timer that may be in effect.
758
+	delete(m.nodeTimers, a.Node)
759
+
757 760
 	// Store the old state and meta data
758 761
 	oldState := state.State
759 762
 	oldMeta := state.Meta
... ...
@@ -783,21 +950,7 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) {
783 783
 			return
784 784
 		}
785 785
 
786
-		inc := m.nextIncarnation()
787
-		for a.Incarnation >= inc {
788
-			inc = m.nextIncarnation()
789
-		}
790
-		state.Incarnation = inc
791
-
792
-		a := alive{
793
-			Incarnation: inc,
794
-			Node:        state.Name,
795
-			Addr:        state.Addr,
796
-			Port:        state.Port,
797
-			Meta:        state.Meta,
798
-			Vsn:         versions,
799
-		}
800
-		m.encodeBroadcastNotify(a.Node, aliveMsg, a, notify)
786
+		m.refute(state, a.Incarnation)
801 787
 		m.logger.Printf("[WARN] memberlist: Refuting an alive message")
802 788
 	} else {
803 789
 		m.encodeBroadcastNotify(a.Node, aliveMsg, a, notify)
... ...
@@ -854,6 +1007,17 @@ func (m *Memberlist) suspectNode(s *suspect) {
854 854
 		return
855 855
 	}
856 856
 
857
+	// See if there's a suspicion timer we can confirm. If the info is new
858
+	// to us we will go ahead and re-gossip it. This allows for multiple
859
+	// independent confirmations to flow even when a node probes a node
860
+	// that's already suspect.
861
+	if timer, ok := m.nodeTimers[s.Node]; ok {
862
+		if timer.Confirm(s.From) {
863
+			m.encodeAndBroadcast(s.Node, suspectMsg, s)
864
+		}
865
+		return
866
+	}
867
+
857 868
 	// Ignore non-alive nodes
858 869
 	if state.State != stateAlive {
859 870
 		return
... ...
@@ -861,24 +1025,7 @@ func (m *Memberlist) suspectNode(s *suspect) {
861 861
 
862 862
 	// If this is us we need to refute, otherwise re-broadcast
863 863
 	if state.Name == m.config.Name {
864
-		inc := m.nextIncarnation()
865
-		for s.Incarnation >= inc {
866
-			inc = m.nextIncarnation()
867
-		}
868
-		state.Incarnation = inc
869
-
870
-		a := alive{
871
-			Incarnation: inc,
872
-			Node:        state.Name,
873
-			Addr:        state.Addr,
874
-			Port:        state.Port,
875
-			Meta:        state.Meta,
876
-			Vsn: []uint8{
877
-				state.PMin, state.PMax, state.PCur,
878
-				state.DMin, state.DMax, state.DCur,
879
-			},
880
-		}
881
-		m.encodeAndBroadcast(s.Node, aliveMsg, a)
864
+		m.refute(state, s.Incarnation)
882 865
 		m.logger.Printf("[WARN] memberlist: Refuting a suspect message (from: %s)", s.From)
883 866
 		return // Do not mark ourself suspect
884 867
 	} else {
... ...
@@ -894,26 +1041,41 @@ func (m *Memberlist) suspectNode(s *suspect) {
894 894
 	changeTime := time.Now()
895 895
 	state.StateChange = changeTime
896 896
 
897
-	// Setup a timeout for this
898
-	timeout := suspicionTimeout(m.config.SuspicionMult, m.estNumNodes(), m.config.ProbeInterval)
899
-	time.AfterFunc(timeout, func() {
897
+	// Setup a suspicion timer. Given that we don't have any known phase
898
+	// relationship with our peers, we set up k such that we hit the nominal
899
+	// timeout two probe intervals short of what we expect given the suspicion
900
+	// multiplier.
901
+	k := m.config.SuspicionMult - 2
902
+
903
+	// If there aren't enough nodes to give the expected confirmations, just
904
+	// set k to 0 to say that we don't expect any. Note we subtract 2 from n
905
+	// here to take out ourselves and the node being probed.
906
+	n := m.estNumNodes()
907
+	if n-2 < k {
908
+		k = 0
909
+	}
910
+
911
+	// Compute the timeouts based on the size of the cluster.
912
+	min := suspicionTimeout(m.config.SuspicionMult, n, m.config.ProbeInterval)
913
+	max := time.Duration(m.config.SuspicionMaxTimeoutMult) * min
914
+	fn := func(numConfirmations int) {
900 915
 		m.nodeLock.Lock()
901 916
 		state, ok := m.nodeMap[s.Node]
902 917
 		timeout := ok && state.State == stateSuspect && state.StateChange == changeTime
903 918
 		m.nodeLock.Unlock()
904 919
 
905 920
 		if timeout {
906
-			m.suspectTimeout(state)
907
-		}
908
-	})
909
-}
921
+			if k > 0 && numConfirmations < k {
922
+				metrics.IncrCounter([]string{"memberlist", "degraded", "timeout"}, 1)
923
+			}
910 924
 
911
-// suspectTimeout is invoked when a suspect timeout has occurred
912
-func (m *Memberlist) suspectTimeout(n *nodeState) {
913
-	// Construct a dead message
914
-	m.logger.Printf("[INFO] memberlist: Marking %s as failed, suspect timeout reached", n.Name)
915
-	d := dead{Incarnation: n.Incarnation, Node: n.Name, From: m.config.Name}
916
-	m.deadNode(&d)
925
+			m.logger.Printf("[INFO] memberlist: Marking %s as failed, suspect timeout reached (%d peer confirmations)",
926
+				state.Name, numConfirmations)
927
+			d := dead{Incarnation: state.Incarnation, Node: state.Name, From: m.config.Name}
928
+			m.deadNode(&d)
929
+		}
930
+	}
931
+	m.nodeTimers[s.Node] = newSuspicion(s.From, k, min, max, fn)
917 932
 }
918 933
 
919 934
 // deadNode is invoked by the network layer when we get a message
... ...
@@ -933,6 +1095,9 @@ func (m *Memberlist) deadNode(d *dead) {
933 933
 		return
934 934
 	}
935 935
 
936
+	// Clear out any suspicion timer that may be in effect.
937
+	delete(m.nodeTimers, d.Node)
938
+
936 939
 	// Ignore if node is already dead
937 940
 	if state.State == stateDead {
938 941
 		return
... ...
@@ -942,24 +1107,7 @@ func (m *Memberlist) deadNode(d *dead) {
942 942
 	if state.Name == m.config.Name {
943 943
 		// If we are not leaving we need to refute
944 944
 		if !m.leave {
945
-			inc := m.nextIncarnation()
946
-			for d.Incarnation >= inc {
947
-				inc = m.nextIncarnation()
948
-			}
949
-			state.Incarnation = inc
950
-
951
-			a := alive{
952
-				Incarnation: inc,
953
-				Node:        state.Name,
954
-				Addr:        state.Addr,
955
-				Port:        state.Port,
956
-				Meta:        state.Meta,
957
-				Vsn: []uint8{
958
-					state.PMin, state.PMax, state.PCur,
959
-					state.DMin, state.DMax, state.DCur,
960
-				},
961
-			}
962
-			m.encodeAndBroadcast(d.Node, aliveMsg, a)
945
+			m.refute(state, d.Incarnation)
963 946
 			m.logger.Printf("[WARN] memberlist: Refuting a dead message (from: %s)", d.From)
964 947
 			return // Do not mark ourself dead
965 948
 		}
... ...
@@ -1001,7 +1149,7 @@ func (m *Memberlist) mergeState(remote []pushNodeState) {
1001 1001
 			m.aliveNode(&a, nil, false)
1002 1002
 
1003 1003
 		case stateDead:
1004
-			// If the remote node belives a node is dead, we prefer to
1004
+			// If the remote node believes a node is dead, we prefer to
1005 1005
 			// suspect that node instead of declaring it dead instantly
1006 1006
 			fallthrough
1007 1007
 		case stateSuspect:
1008 1008
new file mode 100644
... ...
@@ -0,0 +1,130 @@
0
+package memberlist
1
+
2
+import (
3
+	"math"
4
+	"sync/atomic"
5
+	"time"
6
+)
7
+
8
+// suspicion manages the suspect timer for a node and provides an interface
9
+// to accelerate the timeout as we get more independent confirmations that
10
+// a node is suspect.
11
+type suspicion struct {
12
+	// n is the number of independent confirmations we've seen. This must
13
+	// be updated using atomic instructions to prevent contention with the
14
+	// timer callback.
15
+	n int32
16
+
17
+	// k is the number of independent confirmations we'd like to see in
18
+	// order to drive the timer to its minimum value.
19
+	k int32
20
+
21
+	// min is the minimum timer value.
22
+	min time.Duration
23
+
24
+	// max is the maximum timer value.
25
+	max time.Duration
26
+
27
+	// start captures the timestamp when we began the timer. This is used
28
+	// so we can calculate durations to feed the timer during updates in
29
+	// a way the achieves the overall time we'd like.
30
+	start time.Time
31
+
32
+	// timer is the underlying timer that implements the timeout.
33
+	timer *time.Timer
34
+
35
+	// f is the function to call when the timer expires. We hold on to this
36
+	// because there are cases where we call it directly.
37
+	timeoutFn func()
38
+
39
+	// confirmations is a map of "from" nodes that have confirmed a given
40
+	// node is suspect. This prevents double counting.
41
+	confirmations map[string]struct{}
42
+}
43
+
44
+// newSuspicion returns a timer started with the max time, and that will drive
45
+// to the min time after seeing k or more confirmations. The from node will be
46
+// excluded from confirmations since we might get our own suspicion message
47
+// gossiped back to us. The minimum time will be used if no confirmations are
48
+// called for (k <= 0).
49
+func newSuspicion(from string, k int, min time.Duration, max time.Duration, fn func(int)) *suspicion {
50
+	s := &suspicion{
51
+		k:             int32(k),
52
+		min:           min,
53
+		max:           max,
54
+		confirmations: make(map[string]struct{}),
55
+	}
56
+
57
+	// Exclude the from node from any confirmations.
58
+	s.confirmations[from] = struct{}{}
59
+
60
+	// Pass the number of confirmations into the timeout function for
61
+	// easy telemetry.
62
+	s.timeoutFn = func() {
63
+		fn(int(atomic.LoadInt32(&s.n)))
64
+	}
65
+
66
+	// If there aren't any confirmations to be made then take the min
67
+	// time from the start.
68
+	timeout := max
69
+	if k < 1 {
70
+		timeout = min
71
+	}
72
+	s.timer = time.AfterFunc(timeout, s.timeoutFn)
73
+
74
+	// Capture the start time right after starting the timer above so
75
+	// we should always err on the side of a little longer timeout if
76
+	// there's any preemption that separates this and the step above.
77
+	s.start = time.Now()
78
+	return s
79
+}
80
+
81
+// remainingSuspicionTime takes the state variables of the suspicion timer and
82
+// calculates the remaining time to wait before considering a node dead. The
83
+// return value can be negative, so be prepared to fire the timer immediately in
84
+// that case.
85
+func remainingSuspicionTime(n, k int32, elapsed time.Duration, min, max time.Duration) time.Duration {
86
+	frac := math.Log(float64(n)+1.0) / math.Log(float64(k)+1.0)
87
+	raw := max.Seconds() - frac*(max.Seconds()-min.Seconds())
88
+	timeout := time.Duration(math.Floor(1000.0*raw)) * time.Millisecond
89
+	if timeout < min {
90
+		timeout = min
91
+	}
92
+
93
+	// We have to take into account the amount of time that has passed so
94
+	// far, so we get the right overall timeout.
95
+	return timeout - elapsed
96
+}
97
+
98
+// Confirm registers that a possibly new peer has also determined the given
99
+// node is suspect. This returns true if this was new information, and false
100
+// if it was a duplicate confirmation, or if we've got enough confirmations to
101
+// hit the minimum.
102
+func (s *suspicion) Confirm(from string) bool {
103
+	// If we've got enough confirmations then stop accepting them.
104
+	if atomic.LoadInt32(&s.n) >= s.k {
105
+		return false
106
+	}
107
+
108
+	// Only allow one confirmation from each possible peer.
109
+	if _, ok := s.confirmations[from]; ok {
110
+		return false
111
+	}
112
+	s.confirmations[from] = struct{}{}
113
+
114
+	// Compute the new timeout given the current number of confirmations and
115
+	// adjust the timer. If the timeout becomes negative *and* we can cleanly
116
+	// stop the timer then we will call the timeout function directly from
117
+	// here.
118
+	n := atomic.AddInt32(&s.n, 1)
119
+	elapsed := time.Now().Sub(s.start)
120
+	remaining := remainingSuspicionTime(n, s.k, elapsed, s.min, s.max)
121
+	if s.timer.Stop() {
122
+		if remaining > 0 {
123
+			s.timer.Reset(remaining)
124
+		} else {
125
+			go s.timeoutFn()
126
+		}
127
+	}
128
+	return true
129
+}
0 130
new file mode 100644
... ...
@@ -0,0 +1,65 @@
0
+package memberlist
1
+
2
+import (
3
+	"net"
4
+	"time"
5
+)
6
+
7
+// Packet is used to provide some metadata about incoming packets from peers
8
+// over a packet connection, as well as the packet payload.
9
+type Packet struct {
10
+	// Buf has the raw contents of the packet.
11
+	Buf []byte
12
+
13
+	// From has the address of the peer. This is an actual net.Addr so we
14
+	// can expose some concrete details about incoming packets.
15
+	From net.Addr
16
+
17
+	// Timestamp is the time when the packet was received. This should be
18
+	// taken as close as possible to the actual receipt time to help make an
19
+	// accurate RTT measurements during probes.
20
+	Timestamp time.Time
21
+}
22
+
23
+// Transport is used to abstract over communicating with other peers. The packet
24
+// interface is assumed to be best-effort and the stream interface is assumed to
25
+// be reliable.
26
+type Transport interface {
27
+	// FinalAdvertiseAddr is given the user's configured values (which
28
+	// might be empty) and returns the desired IP and port to advertise to
29
+	// the rest of the cluster.
30
+	FinalAdvertiseAddr(ip string, port int) (net.IP, int, error)
31
+
32
+	// WriteTo is a packet-oriented interface that fires off the given
33
+	// payload to the given address in a connectionless fashion. This should
34
+	// return a time stamp that's as close as possible to when the packet
35
+	// was transmitted to help make accurate RTT measurements during probes.
36
+	//
37
+	// This is similar to net.PacketConn, though we didn't want to expose
38
+	// that full set of required methods to keep assumptions about the
39
+	// underlying plumbing to a minimum. We also treat the address here as a
40
+	// string, similar to Dial, so it's network neutral, so this usually is
41
+	// in the form of "host:port".
42
+	WriteTo(b []byte, addr string) (time.Time, error)
43
+
44
+	// PacketCh returns a channel that can be read to receive incoming
45
+	// packets from other peers. How this is set up for listening is left as
46
+	// an exercise for the concrete transport implementations.
47
+	PacketCh() <-chan *Packet
48
+
49
+	// DialTimeout is used to create a connection that allows us to perform
50
+	// two-way communication with a peer. This is generally more expensive
51
+	// than packet connections so is used for more infrequent operations
52
+	// such as anti-entropy or fallback probes if the packet-oriented probe
53
+	// failed.
54
+	DialTimeout(addr string, timeout time.Duration) (net.Conn, error)
55
+
56
+	// StreamCh returns a channel that can be read to handle incoming stream
57
+	// connections from other peers. How this is set up for listening is
58
+	// left as an exercise for the concrete transport implementations.
59
+	StreamCh() <-chan net.Conn
60
+
61
+	// Shutdown is called when memberlist is shutting down; this gives the
62
+	// transport a chance to clean up any listeners.
63
+	Shutdown() error
64
+}
... ...
@@ -9,10 +9,12 @@ import (
9 9
 	"math"
10 10
 	"math/rand"
11 11
 	"net"
12
+	"strconv"
12 13
 	"strings"
13 14
 	"time"
14 15
 
15 16
 	"github.com/hashicorp/go-msgpack/codec"
17
+	"github.com/sean-/seed"
16 18
 )
17 19
 
18 20
 // pushPullScale is the minimum number of nodes
... ...
@@ -22,72 +24,13 @@ import (
22 22
 // while the 65th will triple it.
23 23
 const pushPullScaleThreshold = 32
24 24
 
25
-/*
26
- * Contains an entry for each private block:
27
- * 10.0.0.0/8
28
- * 100.64.0.0/10
29
- * 127.0.0.0/8
30
- * 169.254.0.0/16
31
- * 172.16.0.0/12
32
- * 192.168.0.0/16
33
- */
34
-var privateBlocks []*net.IPNet
35
-
36
-var loopbackBlock *net.IPNet
37
-
38 25
 const (
39 26
 	// Constant litWidth 2-8
40 27
 	lzwLitWidth = 8
41 28
 )
42 29
 
43 30
 func init() {
44
-	// Seed the random number generator
45
-	rand.Seed(time.Now().UnixNano())
46
-
47
-	// Add each private block
48
-	privateBlocks = make([]*net.IPNet, 6)
49
-
50
-	_, block, err := net.ParseCIDR("10.0.0.0/8")
51
-	if err != nil {
52
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
53
-	}
54
-	privateBlocks[0] = block
55
-
56
-	_, block, err = net.ParseCIDR("100.64.0.0/10")
57
-	if err != nil {
58
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
59
-	}
60
-	privateBlocks[1] = block
61
-
62
-	_, block, err = net.ParseCIDR("127.0.0.0/8")
63
-	if err != nil {
64
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
65
-	}
66
-	privateBlocks[2] = block
67
-
68
-	_, block, err = net.ParseCIDR("169.254.0.0/16")
69
-	if err != nil {
70
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
71
-	}
72
-	privateBlocks[3] = block
73
-
74
-	_, block, err = net.ParseCIDR("172.16.0.0/12")
75
-	if err != nil {
76
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
77
-	}
78
-	privateBlocks[4] = block
79
-
80
-	_, block, err = net.ParseCIDR("192.168.0.0/16")
81
-	if err != nil {
82
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
83
-	}
84
-	privateBlocks[5] = block
85
-
86
-	_, block, err = net.ParseCIDR("127.0.0.0/8")
87
-	if err != nil {
88
-		panic(fmt.Sprintf("Bad cidr. Got %v", err))
89
-	}
90
-	loopbackBlock = block
31
+	seed.Init()
91 32
 }
92 33
 
93 34
 // Decode reverses the encode operation on a byte slice input
... ...
@@ -108,42 +51,6 @@ func encode(msgType messageType, in interface{}) (*bytes.Buffer, error) {
108 108
 	return buf, err
109 109
 }
110 110
 
111
-// GetPrivateIP returns the first private IP address found in a list of
112
-// addresses.
113
-func GetPrivateIP(addresses []net.Addr) (net.IP, error) {
114
-	var candidates []net.IP
115
-
116
-	// Find private IPv4 address
117
-	for _, rawAddr := range addresses {
118
-		var ip net.IP
119
-		switch addr := rawAddr.(type) {
120
-		case *net.IPAddr:
121
-			ip = addr.IP
122
-		case *net.IPNet:
123
-			ip = addr.IP
124
-		default:
125
-			continue
126
-		}
127
-
128
-		if ip.To4() == nil {
129
-			continue
130
-		}
131
-		if !IsPrivateIP(ip.String()) {
132
-			continue
133
-		}
134
-		candidates = append(candidates, ip)
135
-	}
136
-	numIps := len(candidates)
137
-	switch numIps {
138
-	case 0:
139
-		return nil, fmt.Errorf("No private IP address found")
140
-	case 1:
141
-		return candidates[0], nil
142
-	default:
143
-		return nil, fmt.Errorf("Multiple private IPs found. Please configure one.")
144
-	}
145
-}
146
-
147 111
 // Returns a random offset between 0 and n
148 112
 func randomOffset(n int) int {
149 113
 	if n == 0 {
... ...
@@ -155,8 +62,9 @@ func randomOffset(n int) int {
155 155
 // suspicionTimeout computes the timeout that should be used when
156 156
 // a node is suspected
157 157
 func suspicionTimeout(suspicionMult, n int, interval time.Duration) time.Duration {
158
-	nodeScale := math.Ceil(math.Log10(float64(n + 1)))
159
-	timeout := time.Duration(suspicionMult) * time.Duration(nodeScale) * interval
158
+	nodeScale := math.Max(1.0, math.Log10(math.Max(1.0, float64(n))))
159
+	// multiply by 1000 to keep some precision because time.Duration is an int64 type
160
+	timeout := time.Duration(suspicionMult) * time.Duration(nodeScale*1000) * interval / 1000
160 161
 	return timeout
161 162
 }
162 163
 
... ...
@@ -189,9 +97,9 @@ func pushPullScale(interval time.Duration, n int) time.Duration {
189 189
 	return time.Duration(multiplier) * interval
190 190
 }
191 191
 
192
-// moveDeadNodes moves all the nodes in the dead state
193
-// to the end of the slice and returns the index of the first dead node.
194
-func moveDeadNodes(nodes []*nodeState) int {
192
+// moveDeadNodes moves nodes that are dead and beyond the gossip to the dead interval
193
+// to the end of the slice and returns the index of the first moved node.
194
+func moveDeadNodes(nodes []*nodeState, gossipToTheDeadTime time.Duration) int {
195 195
 	numDead := 0
196 196
 	n := len(nodes)
197 197
 	for i := 0; i < n-numDead; i++ {
... ...
@@ -199,6 +107,11 @@ func moveDeadNodes(nodes []*nodeState) int {
199 199
 			continue
200 200
 		}
201 201
 
202
+		// Respect the gossip to the dead interval
203
+		if time.Since(nodes[i].StateChange) <= gossipToTheDeadTime {
204
+			continue
205
+		}
206
+
202 207
 		// Move this node to the end
203 208
 		nodes[i], nodes[n-numDead-1] = nodes[n-numDead-1], nodes[i]
204 209
 		numDead++
... ...
@@ -207,9 +120,10 @@ func moveDeadNodes(nodes []*nodeState) int {
207 207
 	return n - numDead
208 208
 }
209 209
 
210
-// kRandomNodes is used to select up to k random nodes, excluding a given
211
-// node and any non-alive nodes. It is possible that less than k nodes are returned.
212
-func kRandomNodes(k int, excludes []string, nodes []*nodeState) []*nodeState {
210
+// kRandomNodes is used to select up to k random nodes, excluding any nodes where
211
+// the filter function returns true. It is possible that less than k nodes are
212
+// returned.
213
+func kRandomNodes(k int, nodes []*nodeState, filterFn func(*nodeState) bool) []*nodeState {
213 214
 	n := len(nodes)
214 215
 	kNodes := make([]*nodeState, 0, k)
215 216
 OUTER:
... ...
@@ -221,16 +135,9 @@ OUTER:
221 221
 		idx := randomOffset(n)
222 222
 		node := nodes[idx]
223 223
 
224
-		// Exclude node if match
225
-		for _, exclude := range excludes {
226
-			if node.Name == exclude {
227
-				continue OUTER
228
-			}
229
-		}
230
-
231
-		// Exclude if not alive
232
-		if node.State != stateAlive {
233
-			continue
224
+		// Give the filter a shot at it.
225
+		if filterFn != nil && filterFn(node) {
226
+			continue OUTER
234 227
 		}
235 228
 
236 229
 		// Check if we have this node already
... ...
@@ -310,27 +217,18 @@ func decodeCompoundMessage(buf []byte) (trunc int, parts [][]byte, err error) {
310 310
 	return
311 311
 }
312 312
 
313
-// Returns if the given IP is in a private block
314
-func IsPrivateIP(ip_str string) bool {
315
-	ip := net.ParseIP(ip_str)
316
-	for _, priv := range privateBlocks {
317
-		if priv.Contains(ip) {
318
-			return true
319
-		}
320
-	}
321
-	return false
322
-}
323
-
324
-// Returns if the given IP is in a loopback block
325
-func isLoopbackIP(ip_str string) bool {
326
-	ip := net.ParseIP(ip_str)
327
-	return loopbackBlock.Contains(ip)
328
-}
329
-
330
-// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
313
+// Given a string of the form "host", "host:port",
314
+// "ipv6::addr" or "[ipv6::address]:port",
331 315
 // return true if the string includes a port.
332 316
 func hasPort(s string) bool {
333
-	return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
317
+	last := strings.LastIndex(s, ":")
318
+	if last == -1 {
319
+		return false
320
+	}
321
+	if s[0] == '[' {
322
+		return s[last-1] == ']'
323
+	}
324
+	return strings.Index(s, ":") == last
334 325
 }
335 326
 
336 327
 // compressPayload takes an opaque input buffer, compresses it
... ...
@@ -390,3 +288,9 @@ func decompressBuffer(c *compress) ([]byte, error) {
390 390
 	// Return the uncompressed bytes
391 391
 	return b.Bytes(), nil
392 392
 }
393
+
394
+// joinHostPort returns the host:port form of an address, for use with a
395
+// transport.
396
+func joinHostPort(host string, port uint16) string {
397
+	return net.JoinHostPort(host, strconv.Itoa(int(port)))
398
+}
393 399
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+MIT License
1
+
2
+Copyright (c) 2017 Sean Chittenden
3
+Copyright (c) 2016 Alex Dadgar
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, 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,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.
22
+
23
+=====
24
+
25
+Bits of Go-lang's `once.Do()` were cribbed and reused here, too.
26
+
27
+Copyright (c) 2009 The Go Authors. All rights reserved.
28
+
29
+Redistribution and use in source and binary forms, with or without
30
+modification, are permitted provided that the following conditions are
31
+met:
32
+
33
+   * Redistributions of source code must retain the above copyright
34
+notice, this list of conditions and the following disclaimer.
35
+   * Redistributions in binary form must reproduce the above
36
+copyright notice, this list of conditions and the following disclaimer
37
+in the documentation and/or other materials provided with the
38
+distribution.
39
+   * Neither the name of Google Inc. nor the names of its
40
+contributors may be used to endorse or promote products derived from
41
+this software without specific prior written permission.
42
+
43
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 54
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+# `seed` - Quickly Seed Go's Random Number Generator
1
+
2
+Boiler-plate to securely [seed](https://en.wikipedia.org/wiki/Random_seed) Go's
3
+random number generator (if possible).  This library isn't anything fancy, it's
4
+just a canonical way of seeding Go's random number generator. Cribbed from
5
+[`Nomad`](https://github.com/hashicorp/nomad/commit/f89a993ec6b91636a3384dd568898245fbc273a1)
6
+before it was moved into
7
+[`Consul`](https://github.com/hashicorp/consul/commit/d695bcaae6e31ee307c11fdf55bb0bf46ea9fcf4)
8
+and made into a helper function, and now further modularized to be a super
9
+lightweight and reusable library.
10
+
11
+Time is better than
12
+[Go's default seed of `1`](https://golang.org/pkg/math/rand/#Seed), but friends
13
+don't let friends use time as a seed to a random number generator.  Use
14
+`seed.MustInit()` instead.
15
+
16
+`seed.Init()` is an idempotent and reentrant call that will return an error if
17
+it can't seed the value the first time it is called.  `Init()` is reentrant.
18
+
19
+`seed.MustInit()` is idempotent and reentrant call that will `panic()` if it
20
+can't seed the value the first time it is called.  `MustInit()` is reentrant.
21
+
22
+## Usage
23
+
24
+```
25
+package mypackage
26
+
27
+import (
28
+  "github.com/sean-/seed"
29
+)
30
+
31
+// MustInit will panic() if it is unable to set a high-entropy random seed:
32
+func init() {
33
+  seed.MustInit()
34
+}
35
+
36
+// Or if you want to not panic() and can actually handle this error:
37
+func init() {
38
+  if secure, err := !seed.Init(); !secure {
39
+    // Handle the error
40
+    //panic(fmt.Sprintf("Unable to securely seed Go's RNG: %v", err))
41
+  }
42
+}
43
+```
0 44
new file mode 100644
... ...
@@ -0,0 +1,84 @@
0
+package seed
1
+
2
+import (
3
+	crand "crypto/rand"
4
+	"fmt"
5
+	"math"
6
+	"math/big"
7
+	"math/rand"
8
+	"sync"
9
+	"sync/atomic"
10
+	"time"
11
+)
12
+
13
+var (
14
+	m      sync.Mutex
15
+	secure int32
16
+	seeded int32
17
+)
18
+
19
+func cryptoSeed() error {
20
+	defer atomic.StoreInt32(&seeded, 1)
21
+
22
+	var err error
23
+	var n *big.Int
24
+	n, err = crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
25
+	if err != nil {
26
+		rand.Seed(time.Now().UTC().UnixNano())
27
+		return err
28
+	}
29
+	rand.Seed(n.Int64())
30
+	atomic.StoreInt32(&secure, 1)
31
+	return nil
32
+}
33
+
34
+// Init provides best-effort seeding (which is better than running with Go's
35
+// default seed of 1).  If `/dev/urandom` is available, Init() will seed Go's
36
+// runtime with entropy from `/dev/urandom` and return true because the runtime
37
+// was securely seeded.  If Init() has already initialized the random number or
38
+// it had failed to securely initialize the random number generation, Init()
39
+// will return false.  See MustInit().
40
+func Init() (seededSecurely bool, err error) {
41
+	if atomic.LoadInt32(&seeded) == 1 {
42
+		return false, nil
43
+	}
44
+
45
+	// Slow-path
46
+	m.Lock()
47
+	defer m.Unlock()
48
+
49
+	if err := cryptoSeed(); err != nil {
50
+		return false, err
51
+	}
52
+
53
+	return true, nil
54
+}
55
+
56
+// MustInit provides guaranteed secure seeding.  If `/dev/urandom` is not
57
+// available, MustInit will panic() with an error indicating why reading from
58
+// `/dev/urandom` failed.  MustInit() will upgrade the seed if for some reason a
59
+// call to Init() failed in the past.
60
+func MustInit() {
61
+	if atomic.LoadInt32(&secure) == 1 {
62
+		return
63
+	}
64
+
65
+	// Slow-path
66
+	m.Lock()
67
+	defer m.Unlock()
68
+
69
+	if err := cryptoSeed(); err != nil {
70
+		panic(fmt.Sprintf("Unable to seed the random number generator: %v", err))
71
+	}
72
+}
73
+
74
+// Secure returns true if a cryptographically secure seed was used to
75
+// initialize rand.
76
+func Secure() bool {
77
+	return atomic.LoadInt32(&secure) == 1
78
+}
79
+
80
+// Seeded returns true if Init has seeded the random number generator.
81
+func Seeded() bool {
82
+	return atomic.LoadInt32(&seeded) == 1
83
+}