1package sockaddr
2
3import (
4	"encoding/binary"
5	"errors"
6	"fmt"
7	"math/big"
8	"net"
9	"regexp"
10	"sort"
11	"strconv"
12	"strings"
13)
14
15var (
16	// Centralize all regexps and regexp.Copy() where necessary.
17	signRE       *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`)
18	whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`)
19	ifNameRE     *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`)
20	ipAddrRE     *regexp.Regexp = regexp.MustCompile(`^   IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`)
21)
22
23// IfAddrs is a slice of IfAddr
24type IfAddrs []IfAddr
25
26func (ifs IfAddrs) Len() int { return len(ifs) }
27
28// CmpIfFunc is the function signature that must be met to be used in the
29// OrderedIfAddrBy multiIfAddrSorter
30type CmpIfAddrFunc func(p1, p2 *IfAddr) int
31
32// multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within.
33type multiIfAddrSorter struct {
34	ifAddrs IfAddrs
35	cmp     []CmpIfAddrFunc
36}
37
38// Sort sorts the argument slice according to the Cmp functions passed to
39// OrderedIfAddrBy.
40func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) {
41	ms.ifAddrs = ifAddrs
42	sort.Sort(ms)
43}
44
45// OrderedIfAddrBy sorts SockAddr by the list of sort function pointers.
46func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter {
47	return &multiIfAddrSorter{
48		cmp: cmpFuncs,
49	}
50}
51
52// Len is part of sort.Interface.
53func (ms *multiIfAddrSorter) Len() int {
54	return len(ms.ifAddrs)
55}
56
57// Less is part of sort.Interface. It is implemented by looping along the Cmp()
58// functions until it finds a comparison that is either less than or greater
59// than.  A return value of 0 defers sorting to the next function in the
60// multisorter (which means the results of sorting may leave the resutls in a
61// non-deterministic order).
62func (ms *multiIfAddrSorter) Less(i, j int) bool {
63	p, q := &ms.ifAddrs[i], &ms.ifAddrs[j]
64	// Try all but the last comparison.
65	var k int
66	for k = 0; k < len(ms.cmp)-1; k++ {
67		cmp := ms.cmp[k]
68		x := cmp(p, q)
69		switch x {
70		case -1:
71			// p < q, so we have a decision.
72			return true
73		case 1:
74			// p > q, so we have a decision.
75			return false
76		}
77		// p == q; try the next comparison.
78	}
79	// All comparisons to here said "equal", so just return whatever the
80	// final comparison reports.
81	switch ms.cmp[k](p, q) {
82	case -1:
83		return true
84	case 1:
85		return false
86	default:
87		// Still a tie! Now what?
88		return false
89		panic("undefined sort order for remaining items in the list")
90	}
91}
92
93// Swap is part of sort.Interface.
94func (ms *multiIfAddrSorter) Swap(i, j int) {
95	ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i]
96}
97
98// AscIfAddress is a sorting function to sort IfAddrs by their respective
99// address type.  Non-equal types are deferred in the sort.
100func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int {
101	return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
102}
103
104// AscIfDefault is a sorting function to sort IfAddrs by whether or not they
105// have a default route or not.  Non-equal types are deferred in the sort.
106//
107// FIXME: This is a particularly expensive sorting operation because of the
108// non-memoized calls to NewRouteInfo().  In an ideal world the routeInfo data
109// once at the start of the sort and pass it along as a context or by wrapping
110// the IfAddr type with this information (this would also solve the inability to
111// return errors and the possibility of failing silently).  Fortunately,
112// N*log(N) where N = 3 is only ~6.2 invocations.  Not ideal, but not worth
113// optimizing today.  The common case is this gets called once or twice.
114// Patches welcome.
115func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int {
116	ri, err := NewRouteInfo()
117	if err != nil {
118		return sortDeferDecision
119	}
120
121	defaultIfName, err := ri.GetDefaultInterfaceName()
122	if err != nil {
123		return sortDeferDecision
124	}
125
126	switch {
127	case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName:
128		return sortDeferDecision
129	case p1Ptr.Interface.Name == defaultIfName:
130		return sortReceiverBeforeArg
131	case p2Ptr.Interface.Name == defaultIfName:
132		return sortArgBeforeReceiver
133	default:
134		return sortDeferDecision
135	}
136}
137
138// AscIfName is a sorting function to sort IfAddrs by their interface names.
139func AscIfName(p1Ptr, p2Ptr *IfAddr) int {
140	return strings.Compare(p1Ptr.Name, p2Ptr.Name)
141}
142
143// AscIfNetworkSize is a sorting function to sort IfAddrs by their respective
144// network mask size.
145func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
146	return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
147}
148
149// AscIfPort is a sorting function to sort IfAddrs by their respective
150// port type.  Non-equal types are deferred in the sort.
151func AscIfPort(p1Ptr, p2Ptr *IfAddr) int {
152	return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
153}
154
155// AscIfPrivate is a sorting function to sort IfAddrs by "private" values before
156// "public" values.  Both IPv4 and IPv6 are compared against RFC6890 (RFC6890
157// includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6
158// includes RFC4193).
159func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
160	return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
161}
162
163// AscIfType is a sorting function to sort IfAddrs by their respective address
164// type.  Non-equal types are deferred in the sort.
165func AscIfType(p1Ptr, p2Ptr *IfAddr) int {
166	return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
167}
168
169// DescIfAddress is identical to AscIfAddress but reverse ordered.
170func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int {
171	return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
172}
173
174// DescIfDefault is identical to AscIfDefault but reverse ordered.
175func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int {
176	return -1 * AscIfDefault(p1Ptr, p2Ptr)
177}
178
179// DescIfName is identical to AscIfName but reverse ordered.
180func DescIfName(p1Ptr, p2Ptr *IfAddr) int {
181	return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name)
182}
183
184// DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered.
185func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
186	return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
187}
188
189// DescIfPort is identical to AscIfPort but reverse ordered.
190func DescIfPort(p1Ptr, p2Ptr *IfAddr) int {
191	return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
192}
193
194// DescIfPrivate is identical to AscIfPrivate but reverse ordered.
195func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
196	return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
197}
198
199// DescIfType is identical to AscIfType but reverse ordered.
200func DescIfType(p1Ptr, p2Ptr *IfAddr) int {
201	return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
202}
203
204// FilterIfByType filters IfAddrs and returns a list of the matching type
205func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) {
206	excludedIfs = make(IfAddrs, 0, len(ifAddrs))
207	matchedIfs = make(IfAddrs, 0, len(ifAddrs))
208
209	for _, ifAddr := range ifAddrs {
210		if ifAddr.SockAddr.Type()&type_ != 0 {
211			matchedIfs = append(matchedIfs, ifAddr)
212		} else {
213			excludedIfs = append(excludedIfs, ifAddr)
214		}
215	}
216	return matchedIfs, excludedIfs
217}
218
219// IfAttr forwards the selector to IfAttr.Attr() for resolution.  If there is
220// more than one IfAddr, only the first IfAddr is used.
221func IfAttr(selectorName string, ifAddr IfAddr) (string, error) {
222	attrName := AttrName(strings.ToLower(selectorName))
223	attrVal, err := ifAddr.Attr(attrName)
224	return attrVal, err
225}
226
227// IfAttrs forwards the selector to IfAttrs.Attr() for resolution.  If there is
228// more than one IfAddr, only the first IfAddr is used.
229func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) {
230	if len(ifAddrs) == 0 {
231		return "", nil
232	}
233
234	attrName := AttrName(strings.ToLower(selectorName))
235	attrVal, err := ifAddrs[0].Attr(attrName)
236	return attrVal, err
237}
238
239// GetAllInterfaces iterates over all available network interfaces and finds all
240// available IP addresses on each interface and converts them to
241// sockaddr.IPAddrs, and returning the result as an array of IfAddr.
242func GetAllInterfaces() (IfAddrs, error) {
243	ifs, err := net.Interfaces()
244	if err != nil {
245		return nil, err
246	}
247
248	ifAddrs := make(IfAddrs, 0, len(ifs))
249	for _, intf := range ifs {
250		addrs, err := intf.Addrs()
251		if err != nil {
252			return nil, err
253		}
254
255		for _, addr := range addrs {
256			var ipAddr IPAddr
257			ipAddr, err = NewIPAddr(addr.String())
258			if err != nil {
259				return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String())
260			}
261
262			ifAddr := IfAddr{
263				SockAddr:  ipAddr,
264				Interface: intf,
265			}
266			ifAddrs = append(ifAddrs, ifAddr)
267		}
268	}
269
270	return ifAddrs, nil
271}
272
273// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default
274// route.
275func GetDefaultInterfaces() (IfAddrs, error) {
276	ri, err := NewRouteInfo()
277	if err != nil {
278		return nil, err
279	}
280
281	defaultIfName, err := ri.GetDefaultInterfaceName()
282	if err != nil {
283		return nil, err
284	}
285
286	var defaultIfs, ifAddrs IfAddrs
287	ifAddrs, err = GetAllInterfaces()
288	for _, ifAddr := range ifAddrs {
289		if ifAddr.Name == defaultIfName {
290			defaultIfs = append(defaultIfs, ifAddr)
291		}
292	}
293
294	return defaultIfs, nil
295}
296
297// GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a
298// default route.  If the system can't determine its IP address or find an RFC
299// 6890 IP address, an empty IfAddrs will be returned instead.  This function is
300// the `eval` equivalent of:
301//
302// ```
303// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}'
304/// ```
305func GetPrivateInterfaces() (IfAddrs, error) {
306	privateIfs, err := GetAllInterfaces()
307	if err != nil {
308		return IfAddrs{}, err
309	}
310	if len(privateIfs) == 0 {
311		return IfAddrs{}, nil
312	}
313
314	privateIfs, _ = FilterIfByType(privateIfs, TypeIP)
315	if len(privateIfs) == 0 {
316		return IfAddrs{}, nil
317	}
318
319	privateIfs, _, err = IfByFlag("forwardable", privateIfs)
320	if err != nil {
321		return IfAddrs{}, err
322	}
323
324	privateIfs, _, err = IfByFlag("up", privateIfs)
325	if err != nil {
326		return IfAddrs{}, err
327	}
328
329	if len(privateIfs) == 0 {
330		return IfAddrs{}, nil
331	}
332
333	OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs)
334
335	privateIfs, _, err = IfByRFC("6890", privateIfs)
336	if err != nil {
337		return IfAddrs{}, err
338	} else if len(privateIfs) == 0 {
339		return IfAddrs{}, nil
340	}
341
342	return privateIfs, nil
343}
344
345// GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a
346// default route.  If the system can't determine its IP address or find a non
347// RFC 6890 IP address, an empty IfAddrs will be returned instead.  This
348// function is the `eval` equivalent of:
349//
350// ```
351// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}'
352/// ```
353func GetPublicInterfaces() (IfAddrs, error) {
354	publicIfs, err := GetAllInterfaces()
355	if err != nil {
356		return IfAddrs{}, err
357	}
358	if len(publicIfs) == 0 {
359		return IfAddrs{}, nil
360	}
361
362	publicIfs, _ = FilterIfByType(publicIfs, TypeIP)
363	if len(publicIfs) == 0 {
364		return IfAddrs{}, nil
365	}
366
367	publicIfs, _, err = IfByFlag("forwardable", publicIfs)
368	if err != nil {
369		return IfAddrs{}, err
370	}
371
372	publicIfs, _, err = IfByFlag("up", publicIfs)
373	if err != nil {
374		return IfAddrs{}, err
375	}
376
377	if len(publicIfs) == 0 {
378		return IfAddrs{}, nil
379	}
380
381	OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs)
382
383	_, publicIfs, err = IfByRFC("6890", publicIfs)
384	if err != nil {
385		return IfAddrs{}, err
386	} else if len(publicIfs) == 0 {
387		return IfAddrs{}, nil
388	}
389
390	return publicIfs, nil
391}
392
393// IfByAddress returns a list of matched and non-matched IfAddrs, or an error if
394// the regexp fails to compile.
395func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
396	re, err := regexp.Compile(inputRe)
397	if err != nil {
398		return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err)
399	}
400
401	matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
402	excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
403	for _, addr := range ifAddrs {
404		if re.MatchString(addr.SockAddr.String()) {
405			matchedAddrs = append(matchedAddrs, addr)
406		} else {
407			excludedAddrs = append(excludedAddrs, addr)
408		}
409	}
410
411	return matchedAddrs, excludedAddrs, nil
412}
413
414// IfByName returns a list of matched and non-matched IfAddrs, or an error if
415// the regexp fails to compile.
416func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
417	re, err := regexp.Compile(inputRe)
418	if err != nil {
419		return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err)
420	}
421
422	matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
423	excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
424	for _, addr := range ifAddrs {
425		if re.MatchString(addr.Name) {
426			matchedAddrs = append(matchedAddrs, addr)
427		} else {
428			excludedAddrs = append(excludedAddrs, addr)
429		}
430	}
431
432	return matchedAddrs, excludedAddrs, nil
433}
434
435// IfByPort returns a list of matched and non-matched IfAddrs, or an error if
436// the regexp fails to compile.
437func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
438	re, err := regexp.Compile(inputRe)
439	if err != nil {
440		return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err)
441	}
442
443	ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
444	matchedIfs = make(IfAddrs, 0, len(ipIfs))
445	excludedIfs = append(IfAddrs(nil), nonIfs...)
446	for _, addr := range ipIfs {
447		ipAddr := ToIPAddr(addr.SockAddr)
448		if ipAddr == nil {
449			continue
450		}
451
452		port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10)
453		if re.MatchString(port) {
454			matchedIfs = append(matchedIfs, addr)
455		} else {
456			excludedIfs = append(excludedIfs, addr)
457		}
458	}
459
460	return matchedIfs, excludedIfs, nil
461}
462
463// IfByRFC returns a list of matched and non-matched IfAddrs that contain the
464// relevant RFC-specified traits.
465func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
466	inputRFC, err := strconv.ParseUint(selectorParam, 10, 64)
467	if err != nil {
468		return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err)
469	}
470
471	matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs))
472	remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
473
474	rfcNetMap := KnownRFCs()
475	rfcNets, ok := rfcNetMap[uint(inputRFC)]
476	if !ok {
477		return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC)
478	}
479
480	for _, ifAddr := range ifAddrs {
481		var contained bool
482		for _, rfcNet := range rfcNets {
483			if rfcNet.Contains(ifAddr.SockAddr) {
484				matchedIfAddrs = append(matchedIfAddrs, ifAddr)
485				contained = true
486				break
487			}
488		}
489		if !contained {
490			remainingIfAddrs = append(remainingIfAddrs, ifAddr)
491		}
492	}
493
494	return matchedIfAddrs, remainingIfAddrs, nil
495}
496
497// IfByRFCs returns a list of matched and non-matched IfAddrs that contain the
498// relevant RFC-specified traits.  Multiple RFCs can be specified and separated
499// by the `|` symbol.  No protection is taken to ensure an IfAddr does not end
500// up in both the included and excluded list.
501func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
502	var includedIfs, excludedIfs IfAddrs
503	for _, rfcStr := range strings.Split(selectorParam, "|") {
504		includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs)
505		if err != nil {
506			return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err)
507		}
508		includedIfs = append(includedIfs, includedRFCIfs...)
509		excludedIfs = append(excludedIfs, excludedRFCIfs...)
510	}
511
512	return includedIfs, excludedIfs, nil
513}
514
515// IfByMaskSize returns a list of matched and non-matched IfAddrs that have the
516// matching mask size.
517func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
518	maskSize, err := strconv.ParseUint(selectorParam, 10, 64)
519	if err != nil {
520		return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err)
521	}
522
523	ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
524	matchedIfs = make(IfAddrs, 0, len(ipIfs))
525	excludedIfs = append(IfAddrs(nil), nonIfs...)
526	for _, addr := range ipIfs {
527		ipAddr := ToIPAddr(addr.SockAddr)
528		if ipAddr == nil {
529			return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String())
530		}
531
532		switch {
533		case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32:
534			return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize)
535		case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128:
536			return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize)
537		}
538
539		if (*ipAddr).Maskbits() == int(maskSize) {
540			matchedIfs = append(matchedIfs, addr)
541		} else {
542			excludedIfs = append(excludedIfs, addr)
543		}
544	}
545
546	return matchedIfs, excludedIfs, nil
547}
548
549// IfByType returns a list of matching and non-matching IfAddr that match the
550// specified type.  For instance:
551//
552// include "type" "IPv4,IPv6"
553//
554// will include any IfAddrs that is either an IPv4 or IPv6 address.  Any
555// addresses on those interfaces that don't match will be included in the
556// remainder results.
557func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
558	matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
559	remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
560
561	ifTypes := strings.Split(strings.ToLower(inputTypes), "|")
562	for _, ifType := range ifTypes {
563		switch ifType {
564		case "ip", "ipv4", "ipv6", "unix":
565			// Valid types
566		default:
567			return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes)
568		}
569	}
570
571	for _, ifAddr := range ifAddrs {
572		for _, ifType := range ifTypes {
573			var matched bool
574			switch {
575			case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0:
576				matched = true
577			case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0:
578				matched = true
579			case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0:
580				matched = true
581			case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0:
582				matched = true
583			}
584
585			if matched {
586				matchingIfAddrs = append(matchingIfAddrs, ifAddr)
587			} else {
588				remainingIfAddrs = append(remainingIfAddrs, ifAddr)
589			}
590		}
591	}
592
593	return matchingIfAddrs, remainingIfAddrs, nil
594}
595
596// IfByFlag returns a list of matching and non-matching IfAddrs that match the
597// specified type.  For instance:
598//
599// include "flag" "up,broadcast"
600//
601// will include any IfAddrs that have both the "up" and "broadcast" flags set.
602// Any addresses on those interfaces that don't match will be omitted from the
603// results.
604func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
605	matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
606	excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
607
608	var wantForwardable,
609		wantGlobalUnicast,
610		wantInterfaceLocalMulticast,
611		wantLinkLocalMulticast,
612		wantLinkLocalUnicast,
613		wantLoopback,
614		wantMulticast,
615		wantUnspecified bool
616	var ifFlags net.Flags
617	var checkFlags, checkAttrs bool
618	for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") {
619		switch flagName {
620		case "broadcast":
621			checkFlags = true
622			ifFlags = ifFlags | net.FlagBroadcast
623		case "down":
624			checkFlags = true
625			ifFlags = (ifFlags &^ net.FlagUp)
626		case "forwardable":
627			checkAttrs = true
628			wantForwardable = true
629		case "global unicast":
630			checkAttrs = true
631			wantGlobalUnicast = true
632		case "interface-local multicast":
633			checkAttrs = true
634			wantInterfaceLocalMulticast = true
635		case "link-local multicast":
636			checkAttrs = true
637			wantLinkLocalMulticast = true
638		case "link-local unicast":
639			checkAttrs = true
640			wantLinkLocalUnicast = true
641		case "loopback":
642			checkAttrs = true
643			checkFlags = true
644			ifFlags = ifFlags | net.FlagLoopback
645			wantLoopback = true
646		case "multicast":
647			checkAttrs = true
648			checkFlags = true
649			ifFlags = ifFlags | net.FlagMulticast
650			wantMulticast = true
651		case "point-to-point":
652			checkFlags = true
653			ifFlags = ifFlags | net.FlagPointToPoint
654		case "unspecified":
655			checkAttrs = true
656			wantUnspecified = true
657		case "up":
658			checkFlags = true
659			ifFlags = ifFlags | net.FlagUp
660		default:
661			return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName)
662		}
663	}
664
665	for _, ifAddr := range ifAddrs {
666		var matched bool
667		if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags {
668			matched = true
669		}
670		if checkAttrs {
671			if ip := ToIPAddr(ifAddr.SockAddr); ip != nil {
672				netIP := (*ip).NetIP()
673				switch {
674				case wantGlobalUnicast && netIP.IsGlobalUnicast():
675					matched = true
676				case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast():
677					matched = true
678				case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast():
679					matched = true
680				case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast():
681					matched = true
682				case wantLoopback && netIP.IsLoopback():
683					matched = true
684				case wantMulticast && netIP.IsMulticast():
685					matched = true
686				case wantUnspecified && netIP.IsUnspecified():
687					matched = true
688				case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr):
689					matched = true
690				}
691			}
692		}
693		if matched {
694			matchedAddrs = append(matchedAddrs, ifAddr)
695		} else {
696			excludedAddrs = append(excludedAddrs, ifAddr)
697		}
698	}
699	return matchedAddrs, excludedAddrs, nil
700}
701
702// IfByNetwork returns an IfAddrs that are equal to or included within the
703// network passed in by selector.
704func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, error) {
705	var includedIfs, excludedIfs IfAddrs
706	for _, netStr := range strings.Split(selectorParam, "|") {
707		netAddr, err := NewIPAddr(netStr)
708		if err != nil {
709			return nil, nil, fmt.Errorf("unable to create an IP address from %+q: %v", netStr, err)
710		}
711
712		for _, ifAddr := range inputIfAddrs {
713			if netAddr.Contains(ifAddr.SockAddr) {
714				includedIfs = append(includedIfs, ifAddr)
715			} else {
716				excludedIfs = append(excludedIfs, ifAddr)
717			}
718		}
719	}
720
721	return includedIfs, excludedIfs, nil
722}
723
724// IfAddrMath will return a new IfAddr struct with a mutated value.
725func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
726	// Regexp used to enforce the sign being a required part of the grammar for
727	// some values.
728	signRe := signRE.Copy()
729
730	switch strings.ToLower(operation) {
731	case "address":
732		// "address" operates on the IP address and is allowed to overflow or
733		// underflow networks, however it will wrap along the underlying address's
734		// underlying type.
735
736		if !signRe.MatchString(value) {
737			return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
738		}
739
740		switch sockType := inputIfAddr.SockAddr.Type(); sockType {
741		case TypeIPv4:
742			// 33 == Accept any uint32 value
743			// TODO(seanc@): Add the ability to parse hex
744			i, err := strconv.ParseInt(value, 10, 33)
745			if err != nil {
746				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
747			}
748
749			ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
750			ipv4Uint32 := uint32(ipv4.Address)
751			ipv4Uint32 += uint32(i)
752			return IfAddr{
753				SockAddr: IPv4Addr{
754					Address: IPv4Address(ipv4Uint32),
755					Mask:    ipv4.Mask,
756				},
757				Interface: inputIfAddr.Interface,
758			}, nil
759		case TypeIPv6:
760			// 64 == Accept any int32 value
761			// TODO(seanc@): Add the ability to parse hex.  Also parse a bignum int.
762			i, err := strconv.ParseInt(value, 10, 64)
763			if err != nil {
764				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
765			}
766
767			ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
768			ipv6BigIntA := new(big.Int)
769			ipv6BigIntA.Set(ipv6.Address)
770			ipv6BigIntB := big.NewInt(i)
771
772			ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB)
773			ipv6Addr.And(ipv6Addr, ipv6HostMask)
774
775			return IfAddr{
776				SockAddr: IPv6Addr{
777					Address: IPv6Address(ipv6Addr),
778					Mask:    ipv6.Mask,
779				},
780				Interface: inputIfAddr.Interface,
781			}, nil
782		default:
783			return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
784		}
785	case "network":
786		// "network" operates on the network address.  Positive values start at the
787		// network address and negative values wrap at the network address, which
788		// means a "-1" value on a network will be the broadcast address after
789		// wrapping is applied.
790
791		if !signRe.MatchString(value) {
792			return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
793		}
794
795		switch sockType := inputIfAddr.SockAddr.Type(); sockType {
796		case TypeIPv4:
797			// 33 == Accept any uint32 value
798			// TODO(seanc@): Add the ability to parse hex
799			i, err := strconv.ParseInt(value, 10, 33)
800			if err != nil {
801				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
802			}
803
804			ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
805			ipv4Uint32 := uint32(ipv4.NetworkAddress())
806
807			// Wrap along network mask boundaries.  EZ-mode wrapping made possible by
808			// use of int64 vs a uint.
809			var wrappedMask int64
810			if i >= 0 {
811				wrappedMask = i
812			} else {
813				wrappedMask = 1 + i + int64(^uint32(ipv4.Mask))
814			}
815
816			ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask))
817
818			return IfAddr{
819				SockAddr: IPv4Addr{
820					Address: IPv4Address(ipv4Uint32),
821					Mask:    ipv4.Mask,
822				},
823				Interface: inputIfAddr.Interface,
824			}, nil
825		case TypeIPv6:
826			// 64 == Accept any int32 value
827			// TODO(seanc@): Add the ability to parse hex.  Also parse a bignum int.
828			i, err := strconv.ParseInt(value, 10, 64)
829			if err != nil {
830				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
831			}
832
833			ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
834			ipv6BigInt := new(big.Int)
835			ipv6BigInt.Set(ipv6.NetworkAddress())
836
837			mask := new(big.Int)
838			mask.Set(ipv6.Mask)
839			if i > 0 {
840				wrappedMask := new(big.Int)
841				wrappedMask.SetInt64(i)
842
843				wrappedMask.AndNot(wrappedMask, mask)
844				ipv6BigInt.Add(ipv6BigInt, wrappedMask)
845			} else {
846				// Mask off any bits that exceed the network size.  Subtract the
847				// wrappedMask from the last usable - 1
848				wrappedMask := new(big.Int)
849				wrappedMask.SetInt64(-1 * i)
850				wrappedMask.Sub(wrappedMask, big.NewInt(1))
851
852				wrappedMask.AndNot(wrappedMask, mask)
853
854				lastUsable := new(big.Int)
855				lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address)
856
857				ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask)
858			}
859
860			return IfAddr{
861				SockAddr: IPv6Addr{
862					Address: IPv6Address(ipv6BigInt),
863					Mask:    ipv6.Mask,
864				},
865				Interface: inputIfAddr.Interface,
866			}, nil
867		default:
868			return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
869		}
870	case "mask":
871		// "mask" operates on the IP address and returns the IP address on
872		// which the given integer mask has been applied. If the applied mask
873		// corresponds to a larger network than the mask of the IP address,
874		// the latter will be replaced by the former.
875		switch sockType := inputIfAddr.SockAddr.Type(); sockType {
876		case TypeIPv4:
877			i, err := strconv.ParseUint(value, 10, 32)
878			if err != nil {
879				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
880			}
881
882			if i > 32 {
883				return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
884			}
885
886			ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
887
888			ipv4Mask := net.CIDRMask(int(i), 32)
889			ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
890
891			maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
892			maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
893
894			maskedIpv4MaskUint32 := uint32(ipv4.Mask)
895
896			if ipv4MaskUint32 < maskedIpv4MaskUint32 {
897				maskedIpv4MaskUint32 = ipv4MaskUint32
898			}
899
900			return IfAddr{
901				SockAddr: IPv4Addr{
902					Address: IPv4Address(maskedIpv4Uint32),
903					Mask:    IPv4Mask(maskedIpv4MaskUint32),
904				},
905				Interface: inputIfAddr.Interface,
906			}, nil
907		case TypeIPv6:
908			i, err := strconv.ParseUint(value, 10, 32)
909			if err != nil {
910				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
911			}
912
913			if i > 128 {
914				return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
915			}
916
917			ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
918
919			ipv6Mask := net.CIDRMask(int(i), 128)
920			ipv6MaskBigInt := new(big.Int)
921			ipv6MaskBigInt.SetBytes(ipv6Mask)
922
923			maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
924			maskedIpv6BigInt := new(big.Int)
925			maskedIpv6BigInt.SetBytes(maskedIpv6)
926
927			maskedIpv6MaskBigInt := new(big.Int)
928			maskedIpv6MaskBigInt.Set(ipv6.Mask)
929
930			if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
931				maskedIpv6MaskBigInt = ipv6MaskBigInt
932			}
933
934			return IfAddr{
935				SockAddr: IPv6Addr{
936					Address: IPv6Address(maskedIpv6BigInt),
937					Mask:    IPv6Mask(maskedIpv6MaskBigInt),
938				},
939				Interface: inputIfAddr.Interface,
940			}, nil
941		default:
942			return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
943		}
944	default:
945		return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
946	}
947}
948
949// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct.  Any
950// failure will result in zero results.
951func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) {
952	outputAddrs := make(IfAddrs, 0, len(inputIfAddrs))
953	for _, ifAddr := range inputIfAddrs {
954		result, err := IfAddrMath(operation, value, ifAddr)
955		if err != nil {
956			return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err)
957		}
958		outputAddrs = append(outputAddrs, result)
959	}
960	return outputAddrs, nil
961}
962
963// IncludeIfs returns an IfAddrs based on the passed in selector.
964func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
965	var includedIfs IfAddrs
966	var err error
967
968	switch strings.ToLower(selectorName) {
969	case "address":
970		includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs)
971	case "flag", "flags":
972		includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs)
973	case "name":
974		includedIfs, _, err = IfByName(selectorParam, inputIfAddrs)
975	case "network":
976		includedIfs, _, err = IfByNetwork(selectorParam, inputIfAddrs)
977	case "port":
978		includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs)
979	case "rfc", "rfcs":
980		includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs)
981	case "size":
982		includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs)
983	case "type":
984		includedIfs, _, err = IfByType(selectorParam, inputIfAddrs)
985	default:
986		return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName)
987	}
988
989	if err != nil {
990		return IfAddrs{}, err
991	}
992
993	return includedIfs, nil
994}
995
996// ExcludeIfs returns an IfAddrs based on the passed in selector.
997func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
998	var excludedIfs IfAddrs
999	var err error
1000
1001	switch strings.ToLower(selectorName) {
1002	case "address":
1003		_, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs)
1004	case "flag", "flags":
1005		_, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs)
1006	case "name":
1007		_, excludedIfs, err = IfByName(selectorParam, inputIfAddrs)
1008	case "network":
1009		_, excludedIfs, err = IfByNetwork(selectorParam, inputIfAddrs)
1010	case "port":
1011		_, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs)
1012	case "rfc", "rfcs":
1013		_, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs)
1014	case "size":
1015		_, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs)
1016	case "type":
1017		_, excludedIfs, err = IfByType(selectorParam, inputIfAddrs)
1018	default:
1019		return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName)
1020	}
1021
1022	if err != nil {
1023		return IfAddrs{}, err
1024	}
1025
1026	return excludedIfs, nil
1027}
1028
1029// SortIfBy returns an IfAddrs sorted based on the passed in selector.  Multiple
1030// sort clauses can be passed in as a comma delimited list without whitespace.
1031func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
1032	sortedIfs := append(IfAddrs(nil), inputIfAddrs...)
1033
1034	clauses := strings.Split(selectorParam, ",")
1035	sortFuncs := make([]CmpIfAddrFunc, len(clauses))
1036
1037	for i, clause := range clauses {
1038		switch strings.TrimSpace(strings.ToLower(clause)) {
1039		case "+address", "address":
1040			// The "address" selector returns an array of IfAddrs
1041			// ordered by the network address.  IfAddrs that are not
1042			// comparable will be at the end of the list and in a
1043			// non-deterministic order.
1044			sortFuncs[i] = AscIfAddress
1045		case "-address":
1046			sortFuncs[i] = DescIfAddress
1047		case "+default", "default":
1048			sortFuncs[i] = AscIfDefault
1049		case "-default":
1050			sortFuncs[i] = DescIfDefault
1051		case "+name", "name":
1052			// The "name" selector returns an array of IfAddrs
1053			// ordered by the interface name.
1054			sortFuncs[i] = AscIfName
1055		case "-name":
1056			sortFuncs[i] = DescIfName
1057		case "+port", "port":
1058			// The "port" selector returns an array of IfAddrs
1059			// ordered by the port, if included in the IfAddr.
1060			// IfAddrs that are not comparable will be at the end of
1061			// the list and in a non-deterministic order.
1062			sortFuncs[i] = AscIfPort
1063		case "-port":
1064			sortFuncs[i] = DescIfPort
1065		case "+private", "private":
1066			// The "private" selector returns an array of IfAddrs
1067			// ordered by private addresses first.  IfAddrs that are
1068			// not comparable will be at the end of the list and in
1069			// a non-deterministic order.
1070			sortFuncs[i] = AscIfPrivate
1071		case "-private":
1072			sortFuncs[i] = DescIfPrivate
1073		case "+size", "size":
1074			// The "size" selector returns an array of IfAddrs
1075			// ordered by the size of the network mask, smaller mask
1076			// (larger number of hosts per network) to largest
1077			// (e.g. a /24 sorts before a /32).
1078			sortFuncs[i] = AscIfNetworkSize
1079		case "-size":
1080			sortFuncs[i] = DescIfNetworkSize
1081		case "+type", "type":
1082			// The "type" selector returns an array of IfAddrs
1083			// ordered by the type of the IfAddr.  The sort order is
1084			// Unix, IPv4, then IPv6.
1085			sortFuncs[i] = AscIfType
1086		case "-type":
1087			sortFuncs[i] = DescIfType
1088		default:
1089			// Return an empty list for invalid sort types.
1090			return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause)
1091		}
1092	}
1093
1094	OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs)
1095
1096	return sortedIfs, nil
1097}
1098
1099// UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching
1100// selector.  UniqueIfAddrsBy assumes the input has already been sorted.
1101func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) {
1102	attrName := strings.ToLower(selectorName)
1103
1104	ifs := make(IfAddrs, 0, len(inputIfAddrs))
1105	var lastMatch string
1106	for _, ifAddr := range inputIfAddrs {
1107		var out string
1108		switch attrName {
1109		case "address":
1110			out = ifAddr.SockAddr.String()
1111		case "name":
1112			out = ifAddr.Name
1113		default:
1114			return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName)
1115		}
1116
1117		switch {
1118		case lastMatch == "", lastMatch != out:
1119			lastMatch = out
1120			ifs = append(ifs, ifAddr)
1121		case lastMatch == out:
1122			continue
1123		}
1124	}
1125
1126	return ifs, nil
1127}
1128
1129// JoinIfAddrs joins an IfAddrs and returns a string
1130func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) {
1131	outputs := make([]string, 0, len(inputIfAddrs))
1132	attrName := AttrName(strings.ToLower(selectorName))
1133
1134	for _, ifAddr := range inputIfAddrs {
1135		var attrVal string
1136		var err error
1137		attrVal, err = ifAddr.Attr(attrName)
1138		if err != nil {
1139			return "", err
1140		}
1141		outputs = append(outputs, attrVal)
1142	}
1143	return strings.Join(outputs, joinStr), nil
1144}
1145
1146// LimitIfAddrs returns a slice of IfAddrs based on the specified limit.
1147func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) {
1148	// Clamp the limit to the length of the array
1149	if int(lim) > len(in) {
1150		lim = uint(len(in))
1151	}
1152
1153	return in[0:lim], nil
1154}
1155
1156// OffsetIfAddrs returns a slice of IfAddrs based on the specified offset.
1157func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) {
1158	var end bool
1159	if off < 0 {
1160		end = true
1161		off = off * -1
1162	}
1163
1164	if off > len(in) {
1165		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))
1166	}
1167
1168	if end {
1169		return in[len(in)-off:], nil
1170	}
1171	return in[off:], nil
1172}
1173
1174func (ifAddr IfAddr) String() string {
1175	return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface)
1176}
1177
1178// parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs
1179// and Solaris.
1180func parseDefaultIfNameFromRoute(routeOut string) (string, error) {
1181	lines := strings.Split(routeOut, "\n")
1182	for _, line := range lines {
1183		kvs := strings.SplitN(line, ":", 2)
1184		if len(kvs) != 2 {
1185			continue
1186		}
1187
1188		if strings.TrimSpace(kvs[0]) == "interface" {
1189			ifName := strings.TrimSpace(kvs[1])
1190			return ifName, nil
1191		}
1192	}
1193
1194	return "", errors.New("No default interface found")
1195}
1196
1197// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for
1198// Linux.
1199func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
1200	lines := strings.Split(routeOut, "\n")
1201	re := whitespaceRE.Copy()
1202	for _, line := range lines {
1203		kvs := re.Split(line, -1)
1204		if len(kvs) < 5 {
1205			continue
1206		}
1207
1208		if kvs[0] == "default" &&
1209			kvs[1] == "via" &&
1210			kvs[3] == "dev" {
1211			ifName := strings.TrimSpace(kvs[4])
1212			return ifName, nil
1213		}
1214	}
1215
1216	return "", errors.New("No default interface found")
1217}
1218
1219// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and
1220// `ipconfig` on Windows.
1221func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) {
1222	defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut)
1223	if err != nil {
1224		return "", err
1225	}
1226
1227	ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut)
1228	if err != nil {
1229		return "", err
1230	}
1231
1232	return ifName, nil
1233}
1234
1235// parseDefaultIPAddrWindowsRoute parses the IP address on the default interface
1236// `netstat -rn`.
1237//
1238// NOTES(sean): Only IPv4 addresses are parsed at this time.  If you have an
1239// IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with
1240// the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6
1241// support added.
1242func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
1243	lines := strings.Split(routeOut, "\n")
1244	re := whitespaceRE.Copy()
1245	for _, line := range lines {
1246		kvs := re.Split(strings.TrimSpace(line), -1)
1247		if len(kvs) < 3 {
1248			continue
1249		}
1250
1251		if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" {
1252			defaultIPAddr := strings.TrimSpace(kvs[3])
1253			return defaultIPAddr, nil
1254		}
1255	}
1256
1257	return "", errors.New("No IP on default interface found")
1258}
1259
1260// parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the
1261// interface name forwarding traffic to the default gateway.
1262func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) {
1263	lines := strings.Split(routeOut, "\n")
1264	ifNameRe := ifNameRE.Copy()
1265	ipAddrRe := ipAddrRE.Copy()
1266	var ifName string
1267	for _, line := range lines {
1268		switch ifNameMatches := ifNameRe.FindStringSubmatch(line); {
1269		case len(ifNameMatches) > 1:
1270			ifName = ifNameMatches[1]
1271			continue
1272		}
1273
1274		switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); {
1275		case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr:
1276			return ifName, nil
1277		}
1278	}
1279
1280	return "", errors.New("No default interface found with matching IP")
1281}
1282