mirror of https://github.com/hashicorp/consul
Sean Chittenden
8 years ago
20 changed files with 4624 additions and 0 deletions
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0 |
||||
================================== |
||||
|
||||
1. Definitions |
||||
-------------- |
||||
|
||||
1.1. "Contributor" |
||||
means each individual or legal entity that creates, contributes to |
||||
the creation of, or owns Covered Software. |
||||
|
||||
1.2. "Contributor Version" |
||||
means the combination of the Contributions of others (if any) used |
||||
by a Contributor and that particular Contributor's Contribution. |
||||
|
||||
1.3. "Contribution" |
||||
means Covered Software of a particular Contributor. |
||||
|
||||
1.4. "Covered Software" |
||||
means Source Code Form to which the initial Contributor has attached |
||||
the notice in Exhibit A, the Executable Form of such Source Code |
||||
Form, and Modifications of such Source Code Form, in each case |
||||
including portions thereof. |
||||
|
||||
1.5. "Incompatible With Secondary Licenses" |
||||
means |
||||
|
||||
(a) that the initial Contributor has attached the notice described |
||||
in Exhibit B to the Covered Software; or |
||||
|
||||
(b) that the Covered Software was made available under the terms of |
||||
version 1.1 or earlier of the License, but not also under the |
||||
terms of a Secondary License. |
||||
|
||||
1.6. "Executable Form" |
||||
means any form of the work other than Source Code Form. |
||||
|
||||
1.7. "Larger Work" |
||||
means a work that combines Covered Software with other material, in |
||||
a separate file or files, that is not Covered Software. |
||||
|
||||
1.8. "License" |
||||
means this document. |
||||
|
||||
1.9. "Licensable" |
||||
means having the right to grant, to the maximum extent possible, |
||||
whether at the time of the initial grant or subsequently, any and |
||||
all of the rights conveyed by this License. |
||||
|
||||
1.10. "Modifications" |
||||
means any of the following: |
||||
|
||||
(a) any file in Source Code Form that results from an addition to, |
||||
deletion from, or modification of the contents of Covered |
||||
Software; or |
||||
|
||||
(b) any new file in Source Code Form that contains any Covered |
||||
Software. |
||||
|
||||
1.11. "Patent Claims" of a Contributor |
||||
means any patent claim(s), including without limitation, method, |
||||
process, and apparatus claims, in any patent Licensable by such |
||||
Contributor that would be infringed, but for the grant of the |
||||
License, by the making, using, selling, offering for sale, having |
||||
made, import, or transfer of either its Contributions or its |
||||
Contributor Version. |
||||
|
||||
1.12. "Secondary License" |
||||
means either the GNU General Public License, Version 2.0, the GNU |
||||
Lesser General Public License, Version 2.1, the GNU Affero General |
||||
Public License, Version 3.0, or any later versions of those |
||||
licenses. |
||||
|
||||
1.13. "Source Code Form" |
||||
means the form of the work preferred for making modifications. |
||||
|
||||
1.14. "You" (or "Your") |
||||
means an individual or a legal entity exercising rights under this |
||||
License. For legal entities, "You" includes any entity that |
||||
controls, is controlled by, or is under common control with You. For |
||||
purposes of this definition, "control" means (a) the power, direct |
||||
or indirect, to cause the direction or management of such entity, |
||||
whether by contract or otherwise, or (b) ownership of more than |
||||
fifty percent (50%) of the outstanding shares or beneficial |
||||
ownership of such entity. |
||||
|
||||
2. License Grants and Conditions |
||||
-------------------------------- |
||||
|
||||
2.1. Grants |
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free, |
||||
non-exclusive license: |
||||
|
||||
(a) under intellectual property rights (other than patent or trademark) |
||||
Licensable by such Contributor to use, reproduce, make available, |
||||
modify, display, perform, distribute, and otherwise exploit its |
||||
Contributions, either on an unmodified basis, with Modifications, or |
||||
as part of a Larger Work; and |
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer |
||||
for sale, have made, import, and otherwise transfer either its |
||||
Contributions or its Contributor Version. |
||||
|
||||
2.2. Effective Date |
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution |
||||
become effective for each Contribution on the date the Contributor first |
||||
distributes such Contribution. |
||||
|
||||
2.3. Limitations on Grant Scope |
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under |
||||
this License. No additional rights or licenses will be implied from the |
||||
distribution or licensing of Covered Software under this License. |
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a |
||||
Contributor: |
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software; |
||||
or |
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's |
||||
modifications of Covered Software, or (ii) the combination of its |
||||
Contributions with other software (except as part of its Contributor |
||||
Version); or |
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of |
||||
its Contributions. |
||||
|
||||
This License does not grant any rights in the trademarks, service marks, |
||||
or logos of any Contributor (except as may be necessary to comply with |
||||
the notice requirements in Section 3.4). |
||||
|
||||
2.4. Subsequent Licenses |
||||
|
||||
No Contributor makes additional grants as a result of Your choice to |
||||
distribute the Covered Software under a subsequent version of this |
||||
License (see Section 10.2) or under the terms of a Secondary License (if |
||||
permitted under the terms of Section 3.3). |
||||
|
||||
2.5. Representation |
||||
|
||||
Each Contributor represents that the Contributor believes its |
||||
Contributions are its original creation(s) or it has sufficient rights |
||||
to grant the rights to its Contributions conveyed by this License. |
||||
|
||||
2.6. Fair Use |
||||
|
||||
This License is not intended to limit any rights You have under |
||||
applicable copyright doctrines of fair use, fair dealing, or other |
||||
equivalents. |
||||
|
||||
2.7. Conditions |
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted |
||||
in Section 2.1. |
||||
|
||||
3. Responsibilities |
||||
------------------- |
||||
|
||||
3.1. Distribution of Source Form |
||||
|
||||
All distribution of Covered Software in Source Code Form, including any |
||||
Modifications that You create or to which You contribute, must be under |
||||
the terms of this License. You must inform recipients that the Source |
||||
Code Form of the Covered Software is governed by the terms of this |
||||
License, and how they can obtain a copy of this License. You may not |
||||
attempt to alter or restrict the recipients' rights in the Source Code |
||||
Form. |
||||
|
||||
3.2. Distribution of Executable Form |
||||
|
||||
If You distribute Covered Software in Executable Form then: |
||||
|
||||
(a) such Covered Software must also be made available in Source Code |
||||
Form, as described in Section 3.1, and You must inform recipients of |
||||
the Executable Form how they can obtain a copy of such Source Code |
||||
Form by reasonable means in a timely manner, at a charge no more |
||||
than the cost of distribution to the recipient; and |
||||
|
||||
(b) You may distribute such Executable Form under the terms of this |
||||
License, or sublicense it under different terms, provided that the |
||||
license for the Executable Form does not attempt to limit or alter |
||||
the recipients' rights in the Source Code Form under this License. |
||||
|
||||
3.3. Distribution of a Larger Work |
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice, |
||||
provided that You also comply with the requirements of this License for |
||||
the Covered Software. If the Larger Work is a combination of Covered |
||||
Software with a work governed by one or more Secondary Licenses, and the |
||||
Covered Software is not Incompatible With Secondary Licenses, this |
||||
License permits You to additionally distribute such Covered Software |
||||
under the terms of such Secondary License(s), so that the recipient of |
||||
the Larger Work may, at their option, further distribute the Covered |
||||
Software under the terms of either this License or such Secondary |
||||
License(s). |
||||
|
||||
3.4. Notices |
||||
|
||||
You may not remove or alter the substance of any license notices |
||||
(including copyright notices, patent notices, disclaimers of warranty, |
||||
or limitations of liability) contained within the Source Code Form of |
||||
the Covered Software, except that You may alter any license notices to |
||||
the extent required to remedy known factual inaccuracies. |
||||
|
||||
3.5. Application of Additional Terms |
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support, |
||||
indemnity or liability obligations to one or more recipients of Covered |
||||
Software. However, You may do so only on Your own behalf, and not on |
||||
behalf of any Contributor. You must make it absolutely clear that any |
||||
such warranty, support, indemnity, or liability obligation is offered by |
||||
You alone, and You hereby agree to indemnify every Contributor for any |
||||
liability incurred by such Contributor as a result of warranty, support, |
||||
indemnity or liability terms You offer. You may include additional |
||||
disclaimers of warranty and limitations of liability specific to any |
||||
jurisdiction. |
||||
|
||||
4. Inability to Comply Due to Statute or Regulation |
||||
--------------------------------------------------- |
||||
|
||||
If it is impossible for You to comply with any of the terms of this |
||||
License with respect to some or all of the Covered Software due to |
||||
statute, judicial order, or regulation then You must: (a) comply with |
||||
the terms of this License to the maximum extent possible; and (b) |
||||
describe the limitations and the code they affect. Such description must |
||||
be placed in a text file included with all distributions of the Covered |
||||
Software under this License. Except to the extent prohibited by statute |
||||
or regulation, such description must be sufficiently detailed for a |
||||
recipient of ordinary skill to be able to understand it. |
||||
|
||||
5. Termination |
||||
-------------- |
||||
|
||||
5.1. The rights granted under this License will terminate automatically |
||||
if You fail to comply with any of its terms. However, if You become |
||||
compliant, then the rights granted under this License from a particular |
||||
Contributor are reinstated (a) provisionally, unless and until such |
||||
Contributor explicitly and finally terminates Your grants, and (b) on an |
||||
ongoing basis, if such Contributor fails to notify You of the |
||||
non-compliance by some reasonable means prior to 60 days after You have |
||||
come back into compliance. Moreover, Your grants from a particular |
||||
Contributor are reinstated on an ongoing basis if such Contributor |
||||
notifies You of the non-compliance by some reasonable means, this is the |
||||
first time You have received notice of non-compliance with this License |
||||
from such Contributor, and You become compliant prior to 30 days after |
||||
Your receipt of the notice. |
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent |
||||
infringement claim (excluding declaratory judgment actions, |
||||
counter-claims, and cross-claims) alleging that a Contributor Version |
||||
directly or indirectly infringes any patent, then the rights granted to |
||||
You by any and all Contributors for the Covered Software under Section |
||||
2.1 of this License shall terminate. |
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all |
||||
end user license agreements (excluding distributors and resellers) which |
||||
have been validly granted by You or Your distributors under this License |
||||
prior to termination shall survive termination. |
||||
|
||||
************************************************************************ |
||||
* * |
||||
* 6. Disclaimer of Warranty * |
||||
* ------------------------- * |
||||
* * |
||||
* Covered Software is provided under this License on an "as is" * |
||||
* basis, without warranty of any kind, either expressed, implied, or * |
||||
* statutory, including, without limitation, warranties that the * |
||||
* Covered Software is free of defects, merchantable, fit for a * |
||||
* particular purpose or non-infringing. The entire risk as to the * |
||||
* quality and performance of the Covered Software is with You. * |
||||
* Should any Covered Software prove defective in any respect, You * |
||||
* (not any Contributor) assume the cost of any necessary servicing, * |
||||
* repair, or correction. This disclaimer of warranty constitutes an * |
||||
* essential part of this License. No use of any Covered Software is * |
||||
* authorized under this License except under this disclaimer. * |
||||
* * |
||||
************************************************************************ |
||||
|
||||
************************************************************************ |
||||
* * |
||||
* 7. Limitation of Liability * |
||||
* -------------------------- * |
||||
* * |
||||
* Under no circumstances and under no legal theory, whether tort * |
||||
* (including negligence), contract, or otherwise, shall any * |
||||
* Contributor, or anyone who distributes Covered Software as * |
||||
* permitted above, be liable to You for any direct, indirect, * |
||||
* special, incidental, or consequential damages of any character * |
||||
* including, without limitation, damages for lost profits, loss of * |
||||
* goodwill, work stoppage, computer failure or malfunction, or any * |
||||
* and all other commercial damages or losses, even if such party * |
||||
* shall have been informed of the possibility of such damages. This * |
||||
* limitation of liability shall not apply to liability for death or * |
||||
* personal injury resulting from such party's negligence to the * |
||||
* extent applicable law prohibits such limitation. Some * |
||||
* jurisdictions do not allow the exclusion or limitation of * |
||||
* incidental or consequential damages, so this exclusion and * |
||||
* limitation may not apply to You. * |
||||
* * |
||||
************************************************************************ |
||||
|
||||
8. Litigation |
||||
------------- |
||||
|
||||
Any litigation relating to this License may be brought only in the |
||||
courts of a jurisdiction where the defendant maintains its principal |
||||
place of business and such litigation shall be governed by laws of that |
||||
jurisdiction, without reference to its conflict-of-law provisions. |
||||
Nothing in this Section shall prevent a party's ability to bring |
||||
cross-claims or counter-claims. |
||||
|
||||
9. Miscellaneous |
||||
---------------- |
||||
|
||||
This License represents the complete agreement concerning the subject |
||||
matter hereof. If any provision of this License is held to be |
||||
unenforceable, such provision shall be reformed only to the extent |
||||
necessary to make it enforceable. Any law or regulation which provides |
||||
that the language of a contract shall be construed against the drafter |
||||
shall not be used to construe this License against a Contributor. |
||||
|
||||
10. Versions of the License |
||||
--------------------------- |
||||
|
||||
10.1. New Versions |
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section |
||||
10.3, no one other than the license steward has the right to modify or |
||||
publish new versions of this License. Each version will be given a |
||||
distinguishing version number. |
||||
|
||||
10.2. Effect of New Versions |
||||
|
||||
You may distribute the Covered Software under the terms of the version |
||||
of the License under which You originally received the Covered Software, |
||||
or under the terms of any subsequent version published by the license |
||||
steward. |
||||
|
||||
10.3. Modified Versions |
||||
|
||||
If you create software not governed by this License, and you want to |
||||
create a new license for such software, you may create and use a |
||||
modified version of this License if you rename the license and remove |
||||
any references to the name of the license steward (except to note that |
||||
such modified license differs from this License). |
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary |
||||
Licenses |
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With |
||||
Secondary Licenses under the terms of this version of the License, the |
||||
notice described in Exhibit B of this License must be attached. |
||||
|
||||
Exhibit A - Source Code Form License Notice |
||||
------------------------------------------- |
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public |
||||
License, v. 2.0. If a copy of the MPL was not distributed with this |
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/. |
||||
|
||||
If it is not possible or desirable to put the notice in a particular |
||||
file, then You may include the notice in a location (such as a LICENSE |
||||
file in a relevant directory) where a recipient would be likely to look |
||||
for such a notice. |
||||
|
||||
You may add additional accurate notices of copyright ownership. |
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice |
||||
--------------------------------------------------------- |
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as |
||||
defined by the Mozilla Public License, v. 2.0. |
@ -0,0 +1,52 @@
|
||||
TOOLS= golang.org/x/tools/cover
|
||||
GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp
|
||||
GOCOVER_FILE?= .cover.out
|
||||
GOCOVERHTML?= coverage.html
|
||||
|
||||
test:: $(GOCOVER_FILE) |
||||
@$(MAKE) -C cmd/sockaddr test
|
||||
|
||||
cover:: coverage_report |
||||
|
||||
$(GOCOVER_FILE):: |
||||
@find . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | xargs -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)"
|
||||
|
||||
@echo 'mode: set' > $(GOCOVER_FILE)
|
||||
@find . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | xargs -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE)
|
||||
|
||||
$(GOCOVERHTML): $(GOCOVER_FILE) |
||||
go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML)
|
||||
|
||||
coverage_report:: $(GOCOVER_FILE) |
||||
go tool cover -html=$(GOCOVER_FILE)
|
||||
|
||||
audit_tools:: |
||||
@go get -u github.com/golang/lint/golint && echo "Installed golint:"
|
||||
@go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:"
|
||||
@go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:"
|
||||
@go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:"
|
||||
@go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:"
|
||||
|
||||
audit:: |
||||
deadcode
|
||||
go tool vet -all *.go
|
||||
go tool vet -shadow=true *.go
|
||||
golint *.go
|
||||
ineffassign .
|
||||
gocyclo -over 65 *.go
|
||||
misspell *.go
|
||||
|
||||
clean:: |
||||
rm -f $(GOCOVER_FILE) $(GOCOVERHTML)
|
||||
|
||||
dev:: |
||||
@go build
|
||||
@make -B -C cmd/sockaddr sockaddr
|
||||
|
||||
install:: |
||||
@go install
|
||||
@make -C cmd/sockaddr install
|
||||
|
||||
doc:: |
||||
echo Visit: http://127.0.0.1:6060/pkg/github.com/hashicorp/go-sockaddr/
|
||||
godoc -http=:6060 -goroot $GOROOT
|
@ -0,0 +1,126 @@
|
||||
package sockaddr |
||||
|
||||
// ifAddrAttrMap is a map of the IfAddr type-specific attributes.
|
||||
var ifAddrAttrMap map[AttrName]func(IfAddr) string |
||||
var ifAddrAttrs []AttrName |
||||
|
||||
func init() { |
||||
ifAddrAttrInit() |
||||
} |
||||
|
||||
// GetPrivateIP returns a string with a single IP address that is part of RFC
|
||||
// 6890 and has a default route. If the system can't determine its IP address
|
||||
// or find an RFC 6890 IP address, an empty string will be returned instead.
|
||||
// This function is the `eval` equivilant of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}'
|
||||
/// ```
|
||||
func GetPrivateIP() (string, error) { |
||||
privateIfs, err := GetPrivateInterfaces() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
if len(privateIfs) < 1 { |
||||
return "", nil |
||||
} |
||||
|
||||
ifAddr := privateIfs[0] |
||||
ip := *ToIPAddr(ifAddr.SockAddr) |
||||
return ip.NetIP().String(), nil |
||||
} |
||||
|
||||
// GetPublicIP returns a string with a single IP address that is NOT part of RFC
|
||||
// 6890 and has a default route. If the system can't determine its IP address
|
||||
// or find a non RFC 6890 IP address, an empty string will be returned instead.
|
||||
// This function is the `eval` equivilant of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}'
|
||||
/// ```
|
||||
func GetPublicIP() (string, error) { |
||||
publicIfs, err := GetPublicInterfaces() |
||||
if err != nil { |
||||
return "", err |
||||
} else if len(publicIfs) < 1 { |
||||
return "", nil |
||||
} |
||||
|
||||
ifAddr := publicIfs[0] |
||||
ip := *ToIPAddr(ifAddr.SockAddr) |
||||
return ip.NetIP().String(), nil |
||||
} |
||||
|
||||
// GetInterfaceIP returns a string with a single IP address sorted by the size
|
||||
// of the network (i.e. IP addresses with a smaller netmask, larger network
|
||||
// size, are sorted first). This function is the `eval` equivilant of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <<ARG>> | sort "type,size" | include "flag" "forwardable" | attr "address" }}'
|
||||
/// ```
|
||||
func GetInterfaceIP(namedIfRE string) (string, error) { |
||||
ifAddrs, err := GetAllInterfaces() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
ifAddrs, _, err = IfByFlag("forwardable", ifAddrs) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
ifAddrs, err = SortIfBy("+type,+size", ifAddrs) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if len(ifAddrs) == 0 { |
||||
return "", err |
||||
} |
||||
|
||||
ip := ToIPAddr(ifAddrs[0].SockAddr) |
||||
if ip == nil { |
||||
return "", err |
||||
} |
||||
|
||||
return IPAddrAttr(*ip, "address"), nil |
||||
} |
||||
|
||||
// IfAddrAttrs returns a list of attributes supported by the IfAddr type
|
||||
func IfAddrAttrs() []AttrName { |
||||
return ifAddrAttrs |
||||
} |
||||
|
||||
// IfAddrAttr returns a string representation of an attribute for the given
|
||||
// IfAddr.
|
||||
func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string { |
||||
fn, found := ifAddrAttrMap[attrName] |
||||
if !found { |
||||
return "" |
||||
} |
||||
|
||||
return fn(ifAddr) |
||||
} |
||||
|
||||
// ifAddrAttrInit is called once at init()
|
||||
func ifAddrAttrInit() { |
||||
// Sorted for human readability
|
||||
ifAddrAttrs = []AttrName{ |
||||
"flags", |
||||
"name", |
||||
} |
||||
|
||||
ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{ |
||||
"flags": func(ifAddr IfAddr) string { |
||||
return ifAddr.Interface.Flags.String() |
||||
}, |
||||
"name": func(ifAddr IfAddr) string { |
||||
return ifAddr.Interface.Name |
||||
}, |
||||
} |
||||
} |
@ -0,0 +1,935 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"net" |
||||
"regexp" |
||||
"sort" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// IfAddrs is a slice of IfAddr
|
||||
type IfAddrs []IfAddr |
||||
|
||||
func (ifs IfAddrs) Len() int { return len(ifs) } |
||||
|
||||
// CmpIfFunc is the function signature that must be met to be used in the
|
||||
// OrderedIfAddrBy multiIfAddrSorter
|
||||
type CmpIfAddrFunc func(p1, p2 *IfAddr) int |
||||
|
||||
// multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within.
|
||||
type multiIfAddrSorter struct { |
||||
ifAddrs IfAddrs |
||||
cmp []CmpIfAddrFunc |
||||
} |
||||
|
||||
// Sort sorts the argument slice according to the Cmp functions passed to
|
||||
// OrderedIfAddrBy.
|
||||
func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) { |
||||
ms.ifAddrs = ifAddrs |
||||
sort.Sort(ms) |
||||
} |
||||
|
||||
// OrderedIfAddrBy sorts SockAddr by the list of sort function pointers.
|
||||
func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter { |
||||
return &multiIfAddrSorter{ |
||||
cmp: cmpFuncs, |
||||
} |
||||
} |
||||
|
||||
// Len is part of sort.Interface.
|
||||
func (ms *multiIfAddrSorter) Len() int { |
||||
return len(ms.ifAddrs) |
||||
} |
||||
|
||||
// Less is part of sort.Interface. It is implemented by looping along the Cmp()
|
||||
// functions until it finds a comparison that is either less than or greater
|
||||
// than. A return value of 0 defers sorting to the next function in the
|
||||
// multisorter (which means the results of sorting may leave the resutls in a
|
||||
// non-deterministic order).
|
||||
func (ms *multiIfAddrSorter) Less(i, j int) bool { |
||||
p, q := &ms.ifAddrs[i], &ms.ifAddrs[j] |
||||
// Try all but the last comparison.
|
||||
var k int |
||||
for k = 0; k < len(ms.cmp)-1; k++ { |
||||
cmp := ms.cmp[k] |
||||
x := cmp(p, q) |
||||
switch x { |
||||
case -1: |
||||
// p < q, so we have a decision.
|
||||
return true |
||||
case 1: |
||||
// p > q, so we have a decision.
|
||||
return false |
||||
} |
||||
// p == q; try the next comparison.
|
||||
} |
||||
// All comparisons to here said "equal", so just return whatever the
|
||||
// final comparison reports.
|
||||
switch ms.cmp[k](p, q) { |
||||
case -1: |
||||
return true |
||||
case 1: |
||||
return false |
||||
default: |
||||
// Still a tie! Now what?
|
||||
return false |
||||
panic("undefined sort order for remaining items in the list") |
||||
} |
||||
} |
||||
|
||||
// Swap is part of sort.Interface.
|
||||
func (ms *multiIfAddrSorter) Swap(i, j int) { |
||||
ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i] |
||||
} |
||||
|
||||
// AscIfAddress is a sorting function to sort IfAddrs by their respective
|
||||
// address type. Non-equal types are deferred in the sort.
|
||||
func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int { |
||||
return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// AscIfName is a sorting function to sort IfAddrs by their interface names.
|
||||
func AscIfName(p1Ptr, p2Ptr *IfAddr) int { |
||||
return strings.Compare(p1Ptr.Name, p2Ptr.Name) |
||||
} |
||||
|
||||
// AscIfNetworkSize is a sorting function to sort IfAddrs by their respective
|
||||
// network mask size.
|
||||
func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int { |
||||
return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// AscIfPort is a sorting function to sort IfAddrs by their respective
|
||||
// port type. Non-equal types are deferred in the sort.
|
||||
func AscIfPort(p1Ptr, p2Ptr *IfAddr) int { |
||||
return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// AscIfPrivate is a sorting function to sort IfAddrs by "private" values before
|
||||
// "public" values. Both IPv4 and IPv6 are compared against RFC6890 (RFC6890
|
||||
// includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6
|
||||
// includes RFC4193).
|
||||
func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int { |
||||
return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// AscIfType is a sorting function to sort IfAddrs by their respective address
|
||||
// type. Non-equal types are deferred in the sort.
|
||||
func AscIfType(p1Ptr, p2Ptr *IfAddr) int { |
||||
return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// DescIfAddress is identical to AscIfAddress but reverse ordered.
|
||||
func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int { |
||||
return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// DescIfName is identical to AscIfName but reverse ordered.
|
||||
func DescIfName(p1Ptr, p2Ptr *IfAddr) int { |
||||
return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name) |
||||
} |
||||
|
||||
// DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered.
|
||||
func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int { |
||||
return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// DescIfPort is identical to AscIfPort but reverse ordered.
|
||||
func DescIfPort(p1Ptr, p2Ptr *IfAddr) int { |
||||
return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// DescIfPrivate is identical to AscIfPrivate but reverse ordered.
|
||||
func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int { |
||||
return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// DescIfType is identical to AscIfType but reverse ordered.
|
||||
func DescIfType(p1Ptr, p2Ptr *IfAddr) int { |
||||
return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
||||
} |
||||
|
||||
// FilterIfByType filters IfAddrs and returns a list of the matching type
|
||||
func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) { |
||||
excludedIfs = make(IfAddrs, 0, len(ifAddrs)) |
||||
matchedIfs = make(IfAddrs, 0, len(ifAddrs)) |
||||
|
||||
for _, ifAddr := range ifAddrs { |
||||
if ifAddr.SockAddr.Type()&type_ != 0 { |
||||
matchedIfs = append(matchedIfs, ifAddr) |
||||
} else { |
||||
excludedIfs = append(excludedIfs, ifAddr) |
||||
} |
||||
} |
||||
return matchedIfs, excludedIfs |
||||
} |
||||
|
||||
// IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is
|
||||
// more than one IfAddr, only the first IfAddr is used.
|
||||
func IfAttr(selectorName string, ifAddrs IfAddrs) (string, error) { |
||||
if len(ifAddrs) == 0 { |
||||
return "", nil |
||||
} |
||||
|
||||
attrName := AttrName(strings.ToLower(selectorName)) |
||||
attrVal, err := ifAddrs[0].Attr(attrName) |
||||
return attrVal, err |
||||
} |
||||
|
||||
// GetAllInterfaces iterates over all available network interfaces and finds all
|
||||
// available IP addresses on each interface and converts them to
|
||||
// sockaddr.IPAddrs, and returning the result as an array of IfAddr.
|
||||
func GetAllInterfaces() (IfAddrs, error) { |
||||
ifs, err := net.Interfaces() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
ifAddrs := make(IfAddrs, 0, len(ifs)) |
||||
for _, intf := range ifs { |
||||
addrs, err := intf.Addrs() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
for _, addr := range addrs { |
||||
var ipAddr IPAddr |
||||
ipAddr, err = NewIPAddr(addr.String()) |
||||
if err != nil { |
||||
return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String()) |
||||
} |
||||
|
||||
ifAddr := IfAddr{ |
||||
SockAddr: ipAddr, |
||||
Interface: intf, |
||||
} |
||||
ifAddrs = append(ifAddrs, ifAddr) |
||||
} |
||||
} |
||||
|
||||
return ifAddrs, nil |
||||
} |
||||
|
||||
// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default
|
||||
// route.
|
||||
func GetDefaultInterfaces() (IfAddrs, error) { |
||||
defaultIfName, err := getDefaultIfName() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
var defaultIfs, ifAddrs IfAddrs |
||||
ifAddrs, err = GetAllInterfaces() |
||||
for _, ifAddr := range ifAddrs { |
||||
if ifAddr.Name == defaultIfName { |
||||
defaultIfs = append(defaultIfs, ifAddr) |
||||
} |
||||
} |
||||
|
||||
return defaultIfs, nil |
||||
} |
||||
|
||||
// GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a
|
||||
// default route. If the system can't determine its IP address or find an RFC
|
||||
// 6890 IP address, an empty IfAddrs will be returned instead. This function is
|
||||
// the `eval` equivilant of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | include "RFC" "6890" }}'
|
||||
/// ```
|
||||
func GetPrivateInterfaces() (IfAddrs, error) { |
||||
privateIfs, err := GetDefaultInterfaces() |
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} |
||||
if len(privateIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
privateIfs, _ = FilterIfByType(privateIfs, TypeIP) |
||||
if len(privateIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
privateIfs, _, err = IfByFlag("forwardable|up", privateIfs) |
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} |
||||
if len(privateIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(privateIfs) |
||||
|
||||
privateIfs, _, err = IfByRFC("6890", privateIfs) |
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} else if len(privateIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
return privateIfs, nil |
||||
} |
||||
|
||||
// GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a
|
||||
// default route. If the system can't determine its IP address or find a non
|
||||
// RFC 6890 IP address, an empty IfAddrs will be returned instead. This
|
||||
// function is the `eval` equivilant of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | exclude "RFC" "6890" }}'
|
||||
/// ```
|
||||
func GetPublicInterfaces() (IfAddrs, error) { |
||||
publicIfs, err := GetDefaultInterfaces() |
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} |
||||
if len(publicIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
publicIfs, _ = FilterIfByType(publicIfs, TypeIP) |
||||
if len(publicIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
publicIfs, _, err = IfByFlag("forwardable|up", publicIfs) |
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} |
||||
if len(publicIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(publicIfs) |
||||
|
||||
_, publicIfs, err = IfByRFC("6890", publicIfs) |
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} else if len(publicIfs) == 0 { |
||||
return IfAddrs{}, nil |
||||
} |
||||
|
||||
return publicIfs, nil |
||||
} |
||||
|
||||
// IfByAddress returns a list of matched and non-matched IfAddrs, or an error if
|
||||
// the regexp fails to compile.
|
||||
func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { |
||||
re, err := regexp.Compile(inputRe) |
||||
if err != nil { |
||||
return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err) |
||||
} |
||||
|
||||
matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
for _, addr := range ifAddrs { |
||||
if re.MatchString(addr.SockAddr.String()) { |
||||
matchedAddrs = append(matchedAddrs, addr) |
||||
} else { |
||||
excludedAddrs = append(excludedAddrs, addr) |
||||
} |
||||
} |
||||
|
||||
return matchedAddrs, excludedAddrs, nil |
||||
} |
||||
|
||||
// IfByName returns a list of matched and non-matched IfAddrs, or an error if
|
||||
// the regexp fails to compile.
|
||||
func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { |
||||
re, err := regexp.Compile(inputRe) |
||||
if err != nil { |
||||
return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err) |
||||
} |
||||
|
||||
matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
for _, addr := range ifAddrs { |
||||
if re.MatchString(addr.Name) { |
||||
matchedAddrs = append(matchedAddrs, addr) |
||||
} else { |
||||
excludedAddrs = append(excludedAddrs, addr) |
||||
} |
||||
} |
||||
|
||||
return matchedAddrs, excludedAddrs, nil |
||||
} |
||||
|
||||
// IfByPort returns a list of matched and non-matched IfAddrs, or an error if
|
||||
// the regexp fails to compile.
|
||||
func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) { |
||||
re, err := regexp.Compile(inputRe) |
||||
if err != nil { |
||||
return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err) |
||||
} |
||||
|
||||
ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP) |
||||
matchedIfs = make(IfAddrs, 0, len(ipIfs)) |
||||
excludedIfs = append(IfAddrs(nil), nonIfs...) |
||||
for _, addr := range ipIfs { |
||||
ipAddr := ToIPAddr(addr.SockAddr) |
||||
if ipAddr == nil { |
||||
continue |
||||
} |
||||
|
||||
port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10) |
||||
if re.MatchString(port) { |
||||
matchedIfs = append(matchedIfs, addr) |
||||
} else { |
||||
excludedIfs = append(excludedIfs, addr) |
||||
} |
||||
} |
||||
|
||||
return matchedIfs, excludedIfs, nil |
||||
} |
||||
|
||||
// IfByRFC returns a list of matched and non-matched IfAddrs that contain the
|
||||
// relevant RFC-specified traits.
|
||||
func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { |
||||
inputRFC, err := strconv.ParseUint(selectorParam, 10, 64) |
||||
if err != nil { |
||||
return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err) |
||||
} |
||||
|
||||
matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
|
||||
rfcNetMap := KnownRFCs() |
||||
rfcNets, ok := rfcNetMap[uint(inputRFC)] |
||||
if !ok { |
||||
return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC) |
||||
} |
||||
|
||||
for _, ifAddr := range ifAddrs { |
||||
var contained bool |
||||
for _, rfcNet := range rfcNets { |
||||
if rfcNet.Contains(ifAddr.SockAddr) { |
||||
matchedIfAddrs = append(matchedIfAddrs, ifAddr) |
||||
contained = true |
||||
break |
||||
} |
||||
} |
||||
if !contained { |
||||
remainingIfAddrs = append(remainingIfAddrs, ifAddr) |
||||
} |
||||
} |
||||
|
||||
return matchedIfAddrs, remainingIfAddrs, nil |
||||
} |
||||
|
||||
// IfByRFCs returns a list of matched and non-matched IfAddrs that contain the
|
||||
// relevant RFC-specified traits. Multiple RFCs can be specified and separated
|
||||
// by the `|` symbol. No protection is taken to ensure an IfAddr does not end
|
||||
// up in both the included and excluded list.
|
||||
func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { |
||||
var includedIfs, excludedIfs IfAddrs |
||||
for _, rfcStr := range strings.Split(selectorParam, "|") { |
||||
includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs) |
||||
if err != nil { |
||||
return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err) |
||||
} |
||||
includedIfs = append(includedIfs, includedRFCIfs...) |
||||
excludedIfs = append(excludedIfs, excludedRFCIfs...) |
||||
} |
||||
|
||||
return includedIfs, excludedIfs, nil |
||||
} |
||||
|
||||
// IfByMaskSize returns a list of matched and non-matched IfAddrs that have the
|
||||
// matching mask size.
|
||||
func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) { |
||||
maskSize, err := strconv.ParseUint(selectorParam, 10, 64) |
||||
if err != nil { |
||||
return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err) |
||||
} |
||||
|
||||
ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP) |
||||
matchedIfs = make(IfAddrs, 0, len(ipIfs)) |
||||
excludedIfs = append(IfAddrs(nil), nonIfs...) |
||||
for _, addr := range ipIfs { |
||||
ipAddr := ToIPAddr(addr.SockAddr) |
||||
if ipAddr == nil { |
||||
return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String()) |
||||
} |
||||
|
||||
switch { |
||||
case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32: |
||||
return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize) |
||||
case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128: |
||||
return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize) |
||||
} |
||||
|
||||
if (*ipAddr).Maskbits() == int(maskSize) { |
||||
matchedIfs = append(matchedIfs, addr) |
||||
} else { |
||||
excludedIfs = append(excludedIfs, addr) |
||||
} |
||||
} |
||||
|
||||
return matchedIfs, excludedIfs, nil |
||||
} |
||||
|
||||
// IfByType returns a list of matching and non-matching IfAddr that match the
|
||||
// specified type. For instance:
|
||||
//
|
||||
// include "type" "IPv4,IPv6"
|
||||
//
|
||||
// will include any IfAddrs that is either an IPv4 or IPv6 address. Any
|
||||
// addresses on those interfaces that don't match will be included in the
|
||||
// remainder results.
|
||||
func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { |
||||
matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
|
||||
ifTypes := strings.Split(strings.ToLower(inputTypes), "|") |
||||
for _, ifType := range ifTypes { |
||||
if ifType != "ip" && ifType != "ipv4" && ifType != "ipv6" && ifType != "unix" { |
||||
return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes) |
||||
} |
||||
} |
||||
|
||||
for _, ifAddr := range ifAddrs { |
||||
for _, ifType := range ifTypes { |
||||
var matched bool |
||||
switch { |
||||
case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0: |
||||
matched = true |
||||
case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0: |
||||
matched = true |
||||
case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0: |
||||
matched = true |
||||
case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0: |
||||
matched = true |
||||
} |
||||
|
||||
if matched { |
||||
matchingIfAddrs = append(matchingIfAddrs, ifAddr) |
||||
} else { |
||||
remainingIfAddrs = append(remainingIfAddrs, ifAddr) |
||||
} |
||||
} |
||||
} |
||||
|
||||
return matchingIfAddrs, remainingIfAddrs, nil |
||||
} |
||||
|
||||
// IfByFlag returns a list of matching and non-matching IfAddrs that match the
|
||||
// specified type. For instance:
|
||||
//
|
||||
// include "flag" "up,broadcast"
|
||||
//
|
||||
// will include any IfAddrs that have both the "up" and "broadcast" flags set.
|
||||
// Any addresses on those interfaces that don't match will be omitted from the
|
||||
// results.
|
||||
func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { |
||||
matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) |
||||
|
||||
var wantForwardable, |
||||
wantGlobalUnicast, |
||||
wantInterfaceLocalMulticast, |
||||
wantLinkLocalMulticast, |
||||
wantLinkLocalUnicast, |
||||
wantLoopback, |
||||
wantMulticast, |
||||
wantUnspecified bool |
||||
var ifFlags net.Flags |
||||
var checkFlags, checkAttrs bool |
||||
for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") { |
||||
switch flagName { |
||||
case "broadcast": |
||||
checkFlags = true |
||||
ifFlags = ifFlags | net.FlagBroadcast |
||||
case "down": |
||||
checkFlags = true |
||||
ifFlags = (ifFlags &^ net.FlagUp) |
||||
case "forwardable": |
||||
checkAttrs = true |
||||
wantForwardable = true |
||||
case "global unicast": |
||||
checkAttrs = true |
||||
wantGlobalUnicast = true |
||||
case "interface-local multicast": |
||||
checkAttrs = true |
||||
wantInterfaceLocalMulticast = true |
||||
case "link-local multicast": |
||||
checkAttrs = true |
||||
wantLinkLocalMulticast = true |
||||
case "link-local unicast": |
||||
checkAttrs = true |
||||
wantLinkLocalUnicast = true |
||||
case "loopback": |
||||
checkAttrs = true |
||||
checkFlags = true |
||||
ifFlags = ifFlags | net.FlagLoopback |
||||
wantLoopback = true |
||||
case "multicast": |
||||
checkAttrs = true |
||||
checkFlags = true |
||||
ifFlags = ifFlags | net.FlagMulticast |
||||
wantMulticast = true |
||||
case "point-to-point": |
||||
checkFlags = true |
||||
ifFlags = ifFlags | net.FlagPointToPoint |
||||
case "unspecified": |
||||
checkAttrs = true |
||||
wantUnspecified = true |
||||
case "up": |
||||
checkFlags = true |
||||
ifFlags = ifFlags | net.FlagUp |
||||
default: |
||||
return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName) |
||||
} |
||||
} |
||||
|
||||
for _, ifAddr := range ifAddrs { |
||||
var matched bool |
||||
if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags { |
||||
matched = true |
||||
} |
||||
if checkAttrs { |
||||
if ip := ToIPAddr(ifAddr.SockAddr); ip != nil { |
||||
netIP := (*ip).NetIP() |
||||
switch { |
||||
case wantGlobalUnicast && netIP.IsGlobalUnicast(): |
||||
matched = true |
||||
case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast(): |
||||
matched = true |
||||
case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast(): |
||||
matched = true |
||||
case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast(): |
||||
matched = true |
||||
case wantLoopback && netIP.IsLoopback(): |
||||
matched = true |
||||
case wantMulticast && netIP.IsMulticast(): |
||||
matched = true |
||||
case wantUnspecified && netIP.IsUnspecified(): |
||||
matched = true |
||||
case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr): |
||||
matched = true |
||||
} |
||||
} |
||||
} |
||||
if matched { |
||||
matchedAddrs = append(matchedAddrs, ifAddr) |
||||
} else { |
||||
excludedAddrs = append(excludedAddrs, ifAddr) |
||||
} |
||||
} |
||||
return matchedAddrs, excludedAddrs, nil |
||||
} |
||||
|
||||
// IncludeIfs returns an IfAddrs based on the passed in selector.
|
||||
func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { |
||||
var includedIfs IfAddrs |
||||
var err error |
||||
|
||||
switch strings.ToLower(selectorName) { |
||||
case "address": |
||||
includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs) |
||||
case "flag", "flags": |
||||
includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs) |
||||
case "name": |
||||
includedIfs, _, err = IfByName(selectorParam, inputIfAddrs) |
||||
case "port": |
||||
includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs) |
||||
case "rfc", "rfcs": |
||||
includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs) |
||||
case "size": |
||||
includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs) |
||||
case "type": |
||||
includedIfs, _, err = IfByType(selectorParam, inputIfAddrs) |
||||
default: |
||||
return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName) |
||||
} |
||||
|
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} |
||||
|
||||
return includedIfs, nil |
||||
} |
||||
|
||||
// ExcludeIfs returns an IfAddrs based on the passed in selector.
|
||||
func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { |
||||
var excludedIfs IfAddrs |
||||
var err error |
||||
|
||||
switch strings.ToLower(selectorName) { |
||||
case "address": |
||||
_, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs) |
||||
case "flag", "flags": |
||||
_, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs) |
||||
case "name": |
||||
_, excludedIfs, err = IfByName(selectorParam, inputIfAddrs) |
||||
case "port": |
||||
_, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs) |
||||
case "rfc", "rfcs": |
||||
_, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs) |
||||
case "size": |
||||
_, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs) |
||||
case "type": |
||||
_, excludedIfs, err = IfByType(selectorParam, inputIfAddrs) |
||||
default: |
||||
return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName) |
||||
} |
||||
|
||||
if err != nil { |
||||
return IfAddrs{}, err |
||||
} |
||||
|
||||
return excludedIfs, nil |
||||
} |
||||
|
||||
// SortIfBy returns an IfAddrs sorted based on the passed in selector. Multiple
|
||||
// sort clauses can be passed in as a comma delimited list without whitespace.
|
||||
func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { |
||||
sortedIfs := append(IfAddrs(nil), inputIfAddrs...) |
||||
|
||||
clauses := strings.Split(selectorParam, ",") |
||||
sortFuncs := make([]CmpIfAddrFunc, len(clauses)) |
||||
|
||||
for i, clause := range clauses { |
||||
switch strings.TrimSpace(strings.ToLower(clause)) { |
||||
case "+address", "address": |
||||
// The "address" selector returns an array of IfAddrs
|
||||
// ordered by the network address. IfAddrs that are not
|
||||
// comparable will be at the end of the list and in a
|
||||
// non-deterministic order.
|
||||
sortFuncs[i] = AscIfAddress |
||||
case "-address": |
||||
sortFuncs[i] = DescIfAddress |
||||
case "+name", "name": |
||||
// The "name" selector returns an array of IfAddrs
|
||||
// ordered by the interface name.
|
||||
sortFuncs[i] = AscIfName |
||||
case "-name": |
||||
sortFuncs[i] = DescIfName |
||||
case "+port", "port": |
||||
// The "port" selector returns an array of IfAddrs
|
||||
// ordered by the port, if included in the IfAddr.
|
||||
// IfAddrs that are not comparable will be at the end of
|
||||
// the list and in a non-deterministic order.
|
||||
sortFuncs[i] = AscIfPort |
||||
case "-port": |
||||
sortFuncs[i] = DescIfPort |
||||
case "+private", "private": |
||||
// The "private" selector returns an array of IfAddrs
|
||||
// ordered by private addresses first. IfAddrs that are
|
||||
// not comparable will be at the end of the list and in
|
||||
// a non-deterministic order.
|
||||
sortFuncs[i] = AscIfPrivate |
||||
case "-private": |
||||
sortFuncs[i] = DescIfPrivate |
||||
case "+size", "size": |
||||
// The "size" selector returns an array of IfAddrs
|
||||
// ordered by the size of the network mask, smaller mask
|
||||
// (larger number of hosts per network) to largest
|
||||
// (e.g. a /24 sorts before a /32).
|
||||
sortFuncs[i] = AscIfNetworkSize |
||||
case "-size": |
||||
sortFuncs[i] = DescIfNetworkSize |
||||
case "+type", "type": |
||||
// The "type" selector returns an array of IfAddrs
|
||||
// ordered by the type of the IfAddr. The sort order is
|
||||
// Unix, IPv4, then IPv6.
|
||||
sortFuncs[i] = AscIfType |
||||
case "-type": |
||||
sortFuncs[i] = DescIfType |
||||
default: |
||||
// Return an empty list for invalid sort types.
|
||||
return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause) |
||||
} |
||||
} |
||||
|
||||
OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs) |
||||
|
||||
return sortedIfs, nil |
||||
} |
||||
|
||||
// UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching
|
||||
// selector. UniqueIfAddrsBy assumes the input has already been sorted.
|
||||
func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) { |
||||
attrName := strings.ToLower(selectorName) |
||||
|
||||
ifs := make(IfAddrs, 0, len(inputIfAddrs)) |
||||
var lastMatch string |
||||
for _, ifAddr := range inputIfAddrs { |
||||
var out string |
||||
switch attrName { |
||||
case "address": |
||||
out = ifAddr.SockAddr.String() |
||||
case "name": |
||||
out = ifAddr.Name |
||||
default: |
||||
return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName) |
||||
} |
||||
|
||||
switch { |
||||
case lastMatch == "", lastMatch != out: |
||||
lastMatch = out |
||||
ifs = append(ifs, ifAddr) |
||||
case lastMatch == out: |
||||
continue |
||||
} |
||||
} |
||||
|
||||
return ifs, nil |
||||
} |
||||
|
||||
// JoinIfAddrs joins an IfAddrs and returns a string
|
||||
func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) { |
||||
outputs := make([]string, 0, len(inputIfAddrs)) |
||||
attrName := AttrName(strings.ToLower(selectorName)) |
||||
|
||||
for _, ifAddr := range inputIfAddrs { |
||||
var attrVal string |
||||
var err error |
||||
attrVal, err = ifAddr.Attr(attrName) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
outputs = append(outputs, attrVal) |
||||
} |
||||
return strings.Join(outputs, joinStr), nil |
||||
} |
||||
|
||||
// LimitIfAddrs returns a slice of IfAddrs based on the specified limit.
|
||||
func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) { |
||||
// Clamp the limit to the length of the array
|
||||
if int(lim) > len(in) { |
||||
lim = uint(len(in)) |
||||
} |
||||
|
||||
return in[0:lim], nil |
||||
} |
||||
|
||||
// OffsetIfAddrs returns a slice of IfAddrs based on the specified offset.
|
||||
func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) { |
||||
var end bool |
||||
if off < 0 { |
||||
end = true |
||||
off = off * -1 |
||||
} |
||||
|
||||
if off > len(in) { |
||||
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)) |
||||
} |
||||
|
||||
if end { |
||||
return in[len(in)-off : len(in)], nil |
||||
} |
||||
return in[off:len(in)], nil |
||||
} |
||||
|
||||
func (ifAddr IfAddr) String() string { |
||||
return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface) |
||||
} |
||||
|
||||
// parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs
|
||||
// and Solaris.
|
||||
func parseDefaultIfNameFromRoute(routeOut string) (string, error) { |
||||
lines := strings.Split(routeOut, "\n") |
||||
for _, line := range lines { |
||||
kvs := strings.SplitN(line, ":", 2) |
||||
if len(kvs) != 2 { |
||||
continue |
||||
} |
||||
|
||||
if strings.TrimSpace(kvs[0]) == "interface" { |
||||
ifName := strings.TrimSpace(kvs[1]) |
||||
return ifName, nil |
||||
} |
||||
} |
||||
|
||||
return "", errors.New("No default interface found") |
||||
} |
||||
|
||||
// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for
|
||||
// Linux.
|
||||
func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) { |
||||
lines := strings.Split(routeOut, "\n") |
||||
re := regexp.MustCompile(`[\s]+`) |
||||
for _, line := range lines { |
||||
kvs := re.Split(line, -1) |
||||
if len(kvs) < 5 { |
||||
continue |
||||
} |
||||
|
||||
if kvs[0] == "default" && |
||||
kvs[1] == "via" && |
||||
kvs[3] == "dev" { |
||||
ifName := strings.TrimSpace(kvs[4]) |
||||
return ifName, nil |
||||
} |
||||
} |
||||
|
||||
return "", errors.New("No default interface found") |
||||
} |
||||
|
||||
// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and
|
||||
// `ipconfig` on Windows.
|
||||
func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) { |
||||
defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return ifName, nil |
||||
} |
||||
|
||||
// parseDefaultIPAddrWindowsRoute parses the IP address on the default interface
|
||||
// `netstat -rn`.
|
||||
//
|
||||
// NOTES(sean): Only IPv4 addresses are parsed at this time. If you have an
|
||||
// IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with
|
||||
// the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6
|
||||
// support added.
|
||||
func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) { |
||||
lines := strings.Split(routeOut, "\n") |
||||
re := regexp.MustCompile(`[\s]+`) |
||||
for _, line := range lines { |
||||
kvs := re.Split(strings.TrimSpace(line), -1) |
||||
if len(kvs) < 3 { |
||||
continue |
||||
} |
||||
|
||||
if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" { |
||||
defaultIPAddr := strings.TrimSpace(kvs[3]) |
||||
return defaultIPAddr, nil |
||||
} |
||||
} |
||||
|
||||
return "", errors.New("No IP on default interface found") |
||||
} |
||||
|
||||
// parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the
|
||||
// interface name forwarding traffic to the default gateway.
|
||||
func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) { |
||||
lines := strings.Split(routeOut, "\n") |
||||
ifNameRE := regexp.MustCompile(`^Ethernet adapter ([^\s:]+):`) |
||||
ipAddrRE := regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) |
||||
var ifName string |
||||
for _, line := range lines { |
||||
switch ifNameMatches := ifNameRE.FindStringSubmatch(line); { |
||||
case len(ifNameMatches) > 1: |
||||
ifName = ifNameMatches[1] |
||||
continue |
||||
} |
||||
|
||||
switch ipAddrMatches := ipAddrRE.FindStringSubmatch(line); { |
||||
case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr: |
||||
return ifName, nil |
||||
} |
||||
} |
||||
|
||||
return "", errors.New("No default interface found with matching IP") |
||||
} |
@ -0,0 +1,30 @@
|
||||
// +build darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"errors" |
||||
"os/exec" |
||||
) |
||||
|
||||
// defaultBSDIfNameCmd is the comamnd to run on BSDs to get the default
|
||||
// interface
|
||||
func defaultBSDIfNameCmd() []string { |
||||
return []string{"/sbin/route", "-n", "get", "default"} |
||||
} |
||||
|
||||
// getDefaultIfName is a *BSD-specific function for extracting the name of the
|
||||
// interface from route(8).
|
||||
func getDefaultIfName() (string, error) { |
||||
var cmd []string = defaultBSDIfNameCmd() |
||||
out, err := exec.Command(cmd[0], cmd[1:]...).Output() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
var ifName string |
||||
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { |
||||
return "", errors.New("No default interface found") |
||||
} |
||||
return ifName, nil |
||||
} |
@ -0,0 +1,10 @@
|
||||
// +build android nacl plan9
|
||||
|
||||
package sockaddr |
||||
|
||||
import "errors" |
||||
|
||||
// getDefaultIfName is the default interface function for unsupported platforms.
|
||||
func getDefaultIfName() (string, error) { |
||||
return "", errors.New("No default interface found (unsupported platform)") |
||||
} |
@ -0,0 +1,28 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"errors" |
||||
"os/exec" |
||||
) |
||||
|
||||
// defaultLinuxIfNameCmd is the comamnd to run on Linux to get the default
|
||||
// interface.
|
||||
func defaultLinuxIfNameCmd() []string { |
||||
return []string{"/sbin/ip", "route"} |
||||
} |
||||
|
||||
// getDefaultIfName is a Linux-specific function for extracting the name of the
|
||||
// interface from ip(8).
|
||||
func getDefaultIfName() (string, error) { |
||||
var cmd []string = defaultLinuxIfNameCmd() |
||||
out, err := exec.Command(cmd[0], cmd[1:]...).Output() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
var ifName string |
||||
if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil { |
||||
return "", errors.New("No default interface found") |
||||
} |
||||
return ifName, nil |
||||
} |
@ -0,0 +1,28 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"errors" |
||||
"os/exec" |
||||
) |
||||
|
||||
// defaultSolarisIfNameCmd is the comamnd to run on Solaris to get the default
|
||||
// interface
|
||||
func defaultSolarisIfNameCmd() []string { |
||||
return []string{"/usr/sbin/route", "-n", "get", "default"} |
||||
} |
||||
|
||||
// getDefaultIfName is an Solaris-specific function for extracting the name of
|
||||
// the interface from route(8).
|
||||
func getDefaultIfName() (string, error) { |
||||
var cmd []string = defaultSolarisIfNameCmd() |
||||
out, err := exec.Command(cmd[0], cmd[1:]...).Output() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
var ifName string |
||||
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { |
||||
return "", errors.New("No default interface found") |
||||
} |
||||
return ifName, nil |
||||
} |
@ -0,0 +1,42 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"errors" |
||||
"os/exec" |
||||
) |
||||
|
||||
// defaultWindowsIfNameCmd is the comamnd to run on Windows to get the default
|
||||
// interface.
|
||||
func defaultWindowsIfNameCmd() []string { |
||||
return []string{"netstat", "-rn"} |
||||
} |
||||
|
||||
// defaultWindowsIfNameCmd is the comamnd to run on Windows to get the default
|
||||
// interface.
|
||||
func defaultWindowsIPConfigCmd() []string { |
||||
return []string{"ipconfig"} |
||||
} |
||||
|
||||
// getDefaultIfName is a Windows-specific function for extracting the name of
|
||||
// the interface from `netstat -rn` and `ipconfig`.
|
||||
func getDefaultIfName() (string, error) { |
||||
ipAddr, err := getWindowsIPOnDefaultRoute() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
} |
||||
|
||||
func getWindowsIPOnDefaultRoute() (string, error) { |
||||
var cmd []string = defaultWindowsIfNameCmd() |
||||
out, err := exec.Command(cmd[0], cmd[1:]...).Output() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
var defaultIPAddr string |
||||
if defaultIPAddr, err = parseDefaultIfNameFromWindowsNetstatRN(string(out)); err != nil { |
||||
return "", errors.New("No IP on default route found") |
||||
} |
||||
return defaultIPAddr, nil |
||||
} |
@ -0,0 +1,65 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net" |
||||
) |
||||
|
||||
// IfAddr is a union of a SockAddr and a net.Interface.
|
||||
type IfAddr struct { |
||||
SockAddr |
||||
net.Interface |
||||
} |
||||
|
||||
// Attr returns the named attribute as a string
|
||||
func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) { |
||||
val := IfAddrAttr(ifAddr, attrName) |
||||
if val != "" { |
||||
return val, nil |
||||
} |
||||
|
||||
return Attr(ifAddr.SockAddr, attrName) |
||||
} |
||||
|
||||
// Attr returns the named attribute as a string
|
||||
func Attr(sa SockAddr, attrName AttrName) (string, error) { |
||||
switch sockType := sa.Type(); { |
||||
case sockType&TypeIP != 0: |
||||
ip := *ToIPAddr(sa) |
||||
attrVal := IPAddrAttr(ip, attrName) |
||||
if attrVal != "" { |
||||
return attrVal, nil |
||||
} |
||||
|
||||
if sockType == TypeIPv4 { |
||||
ipv4 := *ToIPv4Addr(sa) |
||||
attrVal := IPv4AddrAttr(ipv4, attrName) |
||||
if attrVal != "" { |
||||
return attrVal, nil |
||||
} |
||||
} else if sockType == TypeIPv6 { |
||||
ipv6 := *ToIPv6Addr(sa) |
||||
attrVal := IPv6AddrAttr(ipv6, attrName) |
||||
if attrVal != "" { |
||||
return attrVal, nil |
||||
} |
||||
} |
||||
|
||||
case sockType == TypeUnix: |
||||
us := *ToUnixSock(sa) |
||||
attrVal := UnixSockAttr(us, attrName) |
||||
if attrVal != "" { |
||||
return attrVal, nil |
||||
} |
||||
} |
||||
|
||||
// Non type-specific attributes
|
||||
switch attrName { |
||||
case "string": |
||||
return sa.String(), nil |
||||
case "type": |
||||
return sa.Type().String(), nil |
||||
} |
||||
|
||||
return "", fmt.Errorf("unsupported attribute name %q", attrName) |
||||
} |
@ -0,0 +1,151 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net" |
||||
"strings" |
||||
) |
||||
|
||||
// Constants for the sizes of IPv3, IPv4, and IPv6 address types.
|
||||
const ( |
||||
IPv3len = 6 |
||||
IPv4len = 4 |
||||
IPv6len = 16 |
||||
) |
||||
|
||||
// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses,
|
||||
// networks, and socket endpoints.
|
||||
type IPAddr interface { |
||||
SockAddr |
||||
AddressBinString() string |
||||
AddressHexString() string |
||||
Cmp(SockAddr) int |
||||
CmpAddress(SockAddr) int |
||||
CmpPort(SockAddr) int |
||||
FirstUsable() IPAddr |
||||
Host() IPAddr |
||||
IPPort() IPPort |
||||
LastUsable() IPAddr |
||||
Maskbits() int |
||||
NetIP() *net.IP |
||||
NetIPMask() *net.IPMask |
||||
NetIPNet() *net.IPNet |
||||
Network() IPAddr |
||||
Octets() []int |
||||
} |
||||
|
||||
// IPPort is the type for an IP port number for the TCP and UDP IP transports.
|
||||
type IPPort uint16 |
||||
|
||||
// IPPrefixLen is a typed integer representing the prefix length for a given
|
||||
// IPAddr.
|
||||
type IPPrefixLen byte |
||||
|
||||
// ipAddrAttrMap is a map of the IPAddr type-specific attributes.
|
||||
var ipAddrAttrMap map[AttrName]func(IPAddr) string |
||||
var ipAddrAttrs []AttrName |
||||
|
||||
func init() { |
||||
ipAddrInit() |
||||
} |
||||
|
||||
// NewIPAddr creates a new IPAddr from a string. Returns nil if the string is
|
||||
// not an IPv4 or an IPv6 address.
|
||||
func NewIPAddr(addr string) (IPAddr, error) { |
||||
ipv4Addr, err := NewIPv4Addr(addr) |
||||
if err == nil { |
||||
return ipv4Addr, nil |
||||
} |
||||
|
||||
ipv6Addr, err := NewIPv6Addr(addr) |
||||
if err == nil { |
||||
return ipv6Addr, nil |
||||
} |
||||
|
||||
return nil, fmt.Errorf("invalid IPAddr %v", addr) |
||||
} |
||||
|
||||
// IPAddrAttr returns a string representation of an attribute for the given
|
||||
// IPAddr.
|
||||
func IPAddrAttr(ip IPAddr, selector AttrName) string { |
||||
fn, found := ipAddrAttrMap[selector] |
||||
if !found { |
||||
return "" |
||||
} |
||||
|
||||
return fn(ip) |
||||
} |
||||
|
||||
// IPAttrs returns a list of attributes supported by the IPAddr type
|
||||
func IPAttrs() []AttrName { |
||||
return ipAddrAttrs |
||||
} |
||||
|
||||
// MustIPAddr is a helper method that must return an IPAddr or panic on invalid
|
||||
// input.
|
||||
func MustIPAddr(addr string) IPAddr { |
||||
ip, err := NewIPAddr(addr) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err)) |
||||
} |
||||
return ip |
||||
} |
||||
|
||||
// ipAddrInit is called once at init()
|
||||
func ipAddrInit() { |
||||
// Sorted for human readability
|
||||
ipAddrAttrs = []AttrName{ |
||||
"host", |
||||
"address", |
||||
"port", |
||||
"netmask", |
||||
"network", |
||||
"mask_bits", |
||||
"binary", |
||||
"hex", |
||||
"first_usable", |
||||
"last_usable", |
||||
"octets", |
||||
} |
||||
|
||||
ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{ |
||||
"address": func(ip IPAddr) string { |
||||
return ip.NetIP().String() |
||||
}, |
||||
"binary": func(ip IPAddr) string { |
||||
return ip.AddressBinString() |
||||
}, |
||||
"first_usable": func(ip IPAddr) string { |
||||
return ip.FirstUsable().String() |
||||
}, |
||||
"hex": func(ip IPAddr) string { |
||||
return ip.AddressHexString() |
||||
}, |
||||
"host": func(ip IPAddr) string { |
||||
return ip.Host().String() |
||||
}, |
||||
"last_usable": func(ip IPAddr) string { |
||||
return ip.LastUsable().String() |
||||
}, |
||||
"mask_bits": func(ip IPAddr) string { |
||||
return fmt.Sprintf("%d", ip.Maskbits()) |
||||
}, |
||||
"netmask": func(ip IPAddr) string { |
||||
return ip.NetIPMask().String() |
||||
}, |
||||
"network": func(ip IPAddr) string { |
||||
return ip.Network().String() |
||||
}, |
||||
"octets": func(ip IPAddr) string { |
||||
octets := ip.Octets() |
||||
octetStrs := make([]string, 0, len(octets)) |
||||
for _, octet := range octets { |
||||
octetStrs = append(octetStrs, fmt.Sprintf("%d", octet)) |
||||
} |
||||
return strings.Join(octetStrs, " ") |
||||
}, |
||||
"port": func(ip IPAddr) string { |
||||
return fmt.Sprintf("%d", ip.IPPort()) |
||||
}, |
||||
} |
||||
} |
@ -0,0 +1,98 @@
|
||||
package sockaddr |
||||
|
||||
import "bytes" |
||||
|
||||
type IPAddrs []IPAddr |
||||
|
||||
func (s IPAddrs) Len() int { return len(s) } |
||||
func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
||||
|
||||
// // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used
|
||||
// // by the routines in this package. The SortIPAddrsByCmp type is used to
|
||||
// // sort IPAddrs by Cmp()
|
||||
// type SortIPAddrsByCmp struct{ IPAddrs }
|
||||
|
||||
// // Less reports whether the element with index i should sort before the
|
||||
// // element with index j.
|
||||
// func (s SortIPAddrsByCmp) Less(i, j int) bool {
|
||||
// // Sort by Type, then address, then port number.
|
||||
// return Less(s.IPAddrs[i], s.IPAddrs[j])
|
||||
// }
|
||||
|
||||
// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
|
||||
// can be used by the routines in this package. The
|
||||
// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
|
||||
// network (most specific to largest network).
|
||||
type SortIPAddrsByNetworkSize struct{ IPAddrs } |
||||
|
||||
// Less reports whether the element with index i should sort before the
|
||||
// element with index j.
|
||||
func (s SortIPAddrsByNetworkSize) Less(i, j int) bool { |
||||
// Sort masks with a larger binary value (i.e. fewer hosts per network
|
||||
// prefix) after masks with a smaller value (larger number of hosts per
|
||||
// prefix).
|
||||
switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) { |
||||
case 0: |
||||
// Fall through to the second test if the net.IPMasks are the
|
||||
// same.
|
||||
break |
||||
case 1: |
||||
return true |
||||
case -1: |
||||
return false |
||||
default: |
||||
panic("bad, m'kay?") |
||||
} |
||||
|
||||
// Sort IPs based on the length (i.e. prefer IPv4 over IPv6).
|
||||
iLen := len(*s.IPAddrs[i].NetIP()) |
||||
jLen := len(*s.IPAddrs[j].NetIP()) |
||||
if iLen != jLen { |
||||
return iLen > jLen |
||||
} |
||||
|
||||
// Sort IPs based on their network address from lowest to highest.
|
||||
switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) { |
||||
case 0: |
||||
break |
||||
case 1: |
||||
return false |
||||
case -1: |
||||
return true |
||||
default: |
||||
panic("lol wut?") |
||||
} |
||||
|
||||
// If a host does not have a port set, it always sorts after hosts
|
||||
// that have a port (e.g. a host with a /32 and port number is more
|
||||
// specific and should sort first over a host with a /32 but no port
|
||||
// set).
|
||||
if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 { |
||||
return false |
||||
} |
||||
return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort() |
||||
} |
||||
|
||||
// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
|
||||
// can be used by the routines in this package. The
|
||||
// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
|
||||
// network (most specific to largest network).
|
||||
type SortIPAddrsBySpecificMaskLen struct{ IPAddrs } |
||||
|
||||
// Less reports whether the element with index i should sort before the
|
||||
// element with index j.
|
||||
func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool { |
||||
return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits() |
||||
} |
||||
|
||||
// SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can
|
||||
// be used by the routines in this package. The SortIPAddrsByBroadMaskLen
|
||||
// type is used to sort IPAddrs by largest network (i.e. largest subnets
|
||||
// first).
|
||||
type SortIPAddrsByBroadMaskLen struct{ IPAddrs } |
||||
|
||||
// Less reports whether the element with index i should sort before the
|
||||
// element with index j.
|
||||
func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool { |
||||
return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits() |
||||
} |
@ -0,0 +1,505 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"fmt" |
||||
"net" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
type ( |
||||
// IPv4Address is a named type representing an IPv4 address.
|
||||
IPv4Address uint32 |
||||
|
||||
// IPv4Network is a named type representing an IPv4 network.
|
||||
IPv4Network uint32 |
||||
|
||||
// IPv4Mask is a named type representing an IPv4 network mask.
|
||||
IPv4Mask uint32 |
||||
) |
||||
|
||||
// IPv4HostMask is a constant represents a /32 IPv4 Address
|
||||
// (i.e. 255.255.255.255).
|
||||
const IPv4HostMask = IPv4Mask(0xffffffff) |
||||
|
||||
// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes.
|
||||
var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string |
||||
var ipv4AddrAttrs []AttrName |
||||
|
||||
// IPv4Addr implements a convenience wrapper around the union of Go's
|
||||
// built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements
|
||||
// `sockaddr` when the the address family is set to AF_INET
|
||||
// (i.e. `sockaddr_in`).
|
||||
type IPv4Addr struct { |
||||
IPAddr |
||||
Address IPv4Address |
||||
Mask IPv4Mask |
||||
Port IPPort |
||||
} |
||||
|
||||
func init() { |
||||
ipv4AddrInit() |
||||
} |
||||
|
||||
// NewIPv4Addr creates an IPv4Addr from a string. String can be in the form
|
||||
// of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is
|
||||
// assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32`
|
||||
// mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port
|
||||
// initialized to zero). ipv4Str can not be a hostname.
|
||||
//
|
||||
// NOTE: Many net.*() routines will initialize and return an IPv6 address.
|
||||
// To create uint32 values from net.IP, always test to make sure the address
|
||||
// returned can be converted to a 4 byte array using To4().
|
||||
func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) { |
||||
// Parse as an IPv4 CIDR
|
||||
ipAddr, network, err := net.ParseCIDR(ipv4Str) |
||||
if err == nil { |
||||
ipv4 := ipAddr.To4() |
||||
if ipv4 == nil { |
||||
return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str) |
||||
} |
||||
|
||||
// If we see an IPv6 netmask, convert it to an IPv4 mask.
|
||||
netmaskSepPos := strings.LastIndexByte(ipv4Str, '/') |
||||
if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) { |
||||
netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8) |
||||
if err != nil { |
||||
return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err) |
||||
} else if netMask > 128 { |
||||
return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str) |
||||
} |
||||
|
||||
if netMask >= 96 { |
||||
// Convert the IPv6 netmask to an IPv4 netmask
|
||||
network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8) |
||||
} |
||||
} |
||||
ipv4Addr := IPv4Addr{ |
||||
Address: IPv4Address(binary.BigEndian.Uint32(ipv4)), |
||||
Mask: IPv4Mask(binary.BigEndian.Uint32(network.Mask)), |
||||
} |
||||
return ipv4Addr, nil |
||||
} |
||||
|
||||
// Attempt to parse ipv4Str as a /32 host with a port number.
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str) |
||||
if err == nil { |
||||
ipv4 := tcpAddr.IP.To4() |
||||
if ipv4 == nil { |
||||
return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str) |
||||
} |
||||
|
||||
ipv4Uint32 := binary.BigEndian.Uint32(ipv4) |
||||
ipv4Addr := IPv4Addr{ |
||||
Address: IPv4Address(ipv4Uint32), |
||||
Mask: IPv4HostMask, |
||||
Port: IPPort(tcpAddr.Port), |
||||
} |
||||
|
||||
return ipv4Addr, nil |
||||
} |
||||
|
||||
// Parse as a naked IPv4 address
|
||||
ip := net.ParseIP(ipv4Str) |
||||
if ip != nil { |
||||
ipv4 := ip.To4() |
||||
if ipv4 == nil { |
||||
return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str) |
||||
} |
||||
|
||||
ipv4Uint32 := binary.BigEndian.Uint32(ipv4) |
||||
ipv4Addr := IPv4Addr{ |
||||
Address: IPv4Address(ipv4Uint32), |
||||
Mask: IPv4HostMask, |
||||
} |
||||
return ipv4Addr, nil |
||||
} |
||||
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err) |
||||
} |
||||
|
||||
// AddressBinString returns a string with the IPv4Addr's Address represented
|
||||
// as a sequence of '0' and '1' characters. This method is useful for
|
||||
// debugging or by operators who want to inspect an address.
|
||||
func (ipv4 IPv4Addr) AddressBinString() string { |
||||
return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2)) |
||||
} |
||||
|
||||
// AddressHexString returns a string with the IPv4Addr address represented as
|
||||
// a sequence of hex characters. This method is useful for debugging or by
|
||||
// operators who want to inspect an address.
|
||||
func (ipv4 IPv4Addr) AddressHexString() string { |
||||
return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16)) |
||||
} |
||||
|
||||
// Broadcast is an IPv4Addr-only method that returns the broadcast address of
|
||||
// the network.
|
||||
//
|
||||
// NOTE: IPv6 only supports multicast, so this method only exists for
|
||||
// IPv4Addr.
|
||||
func (ipv4 IPv4Addr) Broadcast() IPAddr { |
||||
// Nothing should listen on a broadcast address.
|
||||
return IPv4Addr{ |
||||
Address: IPv4Address(ipv4.BroadcastAddress()), |
||||
Mask: IPv4HostMask, |
||||
} |
||||
} |
||||
|
||||
// BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast
|
||||
// address.
|
||||
func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network { |
||||
return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask)) |
||||
} |
||||
|
||||
// CmpAddress follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its address is lower than arg
|
||||
// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is
|
||||
// of a different type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int { |
||||
ipv4b, ok := sa.(IPv4Addr) |
||||
if !ok { |
||||
return sortDeferDecision |
||||
} |
||||
|
||||
switch { |
||||
case ipv4.Address == ipv4b.Address: |
||||
return sortDeferDecision |
||||
case ipv4.Address < ipv4b.Address: |
||||
return sortReceiverBeforeArg |
||||
default: |
||||
return sortArgBeforeReceiver |
||||
} |
||||
} |
||||
|
||||
// CmpPort follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its port is lower than arg
|
||||
// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr,
|
||||
// regardless of type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int { |
||||
var saPort IPPort |
||||
switch v := sa.(type) { |
||||
case IPv4Addr: |
||||
saPort = v.Port |
||||
case IPv6Addr: |
||||
saPort = v.Port |
||||
default: |
||||
return sortDeferDecision |
||||
} |
||||
|
||||
switch { |
||||
case ipv4.Port == saPort: |
||||
return sortDeferDecision |
||||
case ipv4.Port < saPort: |
||||
return sortReceiverBeforeArg |
||||
default: |
||||
return sortArgBeforeReceiver |
||||
} |
||||
} |
||||
|
||||
// CmpRFC follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because it belongs to the RFC and its
|
||||
// arg does not
|
||||
// - 0 if the receiver and arg both belong to the same RFC or neither do.
|
||||
// - 1 If the arg belongs to the RFC but receiver does not.
|
||||
func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int { |
||||
recvInRFC := IsRFC(rfcNum, ipv4) |
||||
ipv4b, ok := sa.(IPv4Addr) |
||||
if !ok { |
||||
// If the receiver is part of the desired RFC and the SockAddr
|
||||
// argument is not, return -1 so that the receiver sorts before
|
||||
// the non-IPv4 SockAddr. Conversely, if the receiver is not
|
||||
// part of the RFC, punt on sorting and leave it for the next
|
||||
// sorter.
|
||||
if recvInRFC { |
||||
return sortReceiverBeforeArg |
||||
} else { |
||||
return sortDeferDecision |
||||
} |
||||
} |
||||
|
||||
argInRFC := IsRFC(rfcNum, ipv4b) |
||||
switch { |
||||
case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC): |
||||
// If a and b both belong to the RFC, or neither belong to
|
||||
// rfcNum, defer sorting to the next sorter.
|
||||
return sortDeferDecision |
||||
case recvInRFC && !argInRFC: |
||||
return sortReceiverBeforeArg |
||||
default: |
||||
return sortArgBeforeReceiver |
||||
} |
||||
} |
||||
|
||||
// Contains returns true if the SockAddr is contained within the receiver.
|
||||
func (ipv4 IPv4Addr) Contains(sa SockAddr) bool { |
||||
ipv4b, ok := sa.(IPv4Addr) |
||||
if !ok { |
||||
return false |
||||
} |
||||
|
||||
return ipv4.ContainsNetwork(ipv4b) |
||||
} |
||||
|
||||
// ContainsAddress returns true if the IPv4Address is contained within the
|
||||
// receiver.
|
||||
func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool { |
||||
return IPv4Address(ipv4.NetworkAddress()) <= x && |
||||
IPv4Address(ipv4.BroadcastAddress()) >= x |
||||
} |
||||
|
||||
// ContainsNetwork returns true if the network from IPv4Addr is contained
|
||||
// within the receiver.
|
||||
func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool { |
||||
return ipv4.NetworkAddress() <= x.NetworkAddress() && |
||||
ipv4.BroadcastAddress() >= x.BroadcastAddress() |
||||
} |
||||
|
||||
// DialPacketArgs returns the arguments required to be passed to
|
||||
// net.DialUDP(). If the Mask of ipv4 is not a /32 or the Port is 0,
|
||||
// DialPacketArgs() will fail. See Host() to create an IPv4Addr with its
|
||||
// mask set to /32.
|
||||
func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) { |
||||
if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 { |
||||
return "udp4", "" |
||||
} |
||||
return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) |
||||
} |
||||
|
||||
// DialStreamArgs returns the arguments required to be passed to
|
||||
// net.DialTCP(). If the Mask of ipv4 is not a /32 or the Port is 0,
|
||||
// DialStreamArgs() will fail. See Host() to create an IPv4Addr with its
|
||||
// mask set to /32.
|
||||
func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) { |
||||
if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 { |
||||
return "tcp4", "" |
||||
} |
||||
return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) |
||||
} |
||||
|
||||
// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
|
||||
func (ipv4 IPv4Addr) Equal(sa SockAddr) bool { |
||||
ipv4b, ok := sa.(IPv4Addr) |
||||
if !ok { |
||||
return false |
||||
} |
||||
|
||||
if ipv4.Port != ipv4b.Port { |
||||
return false |
||||
} |
||||
|
||||
if ipv4.Address != ipv4b.Address { |
||||
return false |
||||
} |
||||
|
||||
if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() { |
||||
return false |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
// FirstUsable returns an IPv4Addr set to the first address following the
|
||||
// network prefix. The first usable address in a network is normally the
|
||||
// gateway and should not be used except by devices forwarding packets
|
||||
// between two administratively distinct networks (i.e. a router). This
|
||||
// function does not discriminate against first usable vs "first address that
|
||||
// should be used." For example, FirstUsable() on "192.168.1.10/24" would
|
||||
// return the address "192.168.1.1/24".
|
||||
func (ipv4 IPv4Addr) FirstUsable() IPAddr { |
||||
addr := ipv4.NetworkAddress() |
||||
|
||||
// If /32, return the address itself. If /31 assume a point-to-point
|
||||
// link and return the lower address.
|
||||
if ipv4.Maskbits() < 31 { |
||||
addr++ |
||||
} |
||||
|
||||
return IPv4Addr{ |
||||
Address: IPv4Address(addr), |
||||
Mask: IPv4HostMask, |
||||
} |
||||
} |
||||
|
||||
// Host returns a copy of ipv4 with its mask set to /32 so that it can be
|
||||
// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
|
||||
// ListenStreamArgs().
|
||||
func (ipv4 IPv4Addr) Host() IPAddr { |
||||
// Nothing should listen on a broadcast address.
|
||||
return IPv4Addr{ |
||||
Address: ipv4.Address, |
||||
Mask: IPv4HostMask, |
||||
Port: ipv4.Port, |
||||
} |
||||
} |
||||
|
||||
// IPPort returns the Port number attached to the IPv4Addr
|
||||
func (ipv4 IPv4Addr) IPPort() IPPort { |
||||
return ipv4.Port |
||||
} |
||||
|
||||
// LastUsable returns the last address before the broadcast address in a
|
||||
// given network.
|
||||
func (ipv4 IPv4Addr) LastUsable() IPAddr { |
||||
addr := ipv4.BroadcastAddress() |
||||
|
||||
// If /32, return the address itself. If /31 assume a point-to-point
|
||||
// link and return the upper address.
|
||||
if ipv4.Maskbits() < 31 { |
||||
addr-- |
||||
} |
||||
|
||||
return IPv4Addr{ |
||||
Address: IPv4Address(addr), |
||||
Mask: IPv4HostMask, |
||||
} |
||||
} |
||||
|
||||
// ListenPacketArgs returns the arguments required to be passed to
|
||||
// net.ListenUDP(). If the Mask of ipv4 is not a /32, ListenPacketArgs()
|
||||
// will fail. See Host() to create an IPv4Addr with its mask set to /32.
|
||||
func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) { |
||||
if ipv4.Mask != IPv4HostMask { |
||||
return "udp4", "" |
||||
} |
||||
return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) |
||||
} |
||||
|
||||
// ListenStreamArgs returns the arguments required to be passed to
|
||||
// net.ListenTCP(). If the Mask of ipv4 is not a /32, ListenStreamArgs()
|
||||
// will fail. See Host() to create an IPv4Addr with its mask set to /32.
|
||||
func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) { |
||||
if ipv4.Mask != IPv4HostMask { |
||||
return "tcp4", "" |
||||
} |
||||
return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) |
||||
} |
||||
|
||||
// Maskbits returns the number of network mask bits in a given IPv4Addr. For
|
||||
// example, the Maskbits() of "192.168.1.1/24" would return 24.
|
||||
func (ipv4 IPv4Addr) Maskbits() int { |
||||
mask := make(net.IPMask, IPv4len) |
||||
binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask)) |
||||
maskOnes, _ := mask.Size() |
||||
return maskOnes |
||||
} |
||||
|
||||
// MustIPv4Addr is a helper method that must return an IPv4Addr or panic on
|
||||
// invalid input.
|
||||
func MustIPv4Addr(addr string) IPv4Addr { |
||||
ipv4, err := NewIPv4Addr(addr) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err)) |
||||
} |
||||
return ipv4 |
||||
} |
||||
|
||||
// NetIP returns the address as a net.IP (address is always presized to
|
||||
// IPv4).
|
||||
func (ipv4 IPv4Addr) NetIP() *net.IP { |
||||
x := make(net.IP, IPv4len) |
||||
binary.BigEndian.PutUint32(x, uint32(ipv4.Address)) |
||||
return &x |
||||
} |
||||
|
||||
// NetIPMask create a new net.IPMask from the IPv4Addr.
|
||||
func (ipv4 IPv4Addr) NetIPMask() *net.IPMask { |
||||
ipv4Mask := net.IPMask{} |
||||
ipv4Mask = make(net.IPMask, IPv4len) |
||||
binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask)) |
||||
return &ipv4Mask |
||||
} |
||||
|
||||
// NetIPNet create a new net.IPNet from the IPv4Addr.
|
||||
func (ipv4 IPv4Addr) NetIPNet() *net.IPNet { |
||||
ipv4net := &net.IPNet{} |
||||
ipv4net.IP = make(net.IP, IPv4len) |
||||
binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress())) |
||||
ipv4net.Mask = *ipv4.NetIPMask() |
||||
return ipv4net |
||||
} |
||||
|
||||
// Network returns the network prefix or network address for a given network.
|
||||
func (ipv4 IPv4Addr) Network() IPAddr { |
||||
return IPv4Addr{ |
||||
Address: IPv4Address(ipv4.NetworkAddress()), |
||||
Mask: ipv4.Mask, |
||||
} |
||||
} |
||||
|
||||
// NetworkAddress returns an IPv4Network of the IPv4Addr's network address.
|
||||
func (ipv4 IPv4Addr) NetworkAddress() IPv4Network { |
||||
return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask)) |
||||
} |
||||
|
||||
// Octets returns a slice of the four octets in an IPv4Addr's Address. The
|
||||
// order of the bytes is big endian.
|
||||
func (ipv4 IPv4Addr) Octets() []int { |
||||
return []int{ |
||||
int(ipv4.Address >> 24), |
||||
int((ipv4.Address >> 16) & 0xff), |
||||
int((ipv4.Address >> 8) & 0xff), |
||||
int(ipv4.Address & 0xff), |
||||
} |
||||
} |
||||
|
||||
// String returns a string representation of the IPv4Addr
|
||||
func (ipv4 IPv4Addr) String() string { |
||||
if ipv4.Port != 0 { |
||||
return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) |
||||
} |
||||
|
||||
if ipv4.Maskbits() == 32 { |
||||
return ipv4.NetIP().String() |
||||
} |
||||
|
||||
return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits()) |
||||
} |
||||
|
||||
// Type is used as a type switch and returns TypeIPv4
|
||||
func (IPv4Addr) Type() SockAddrType { |
||||
return TypeIPv4 |
||||
} |
||||
|
||||
// IPv4AddrAttr returns a string representation of an attribute for the given
|
||||
// IPv4Addr.
|
||||
func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string { |
||||
fn, found := ipv4AddrAttrMap[selector] |
||||
if !found { |
||||
return "" |
||||
} |
||||
|
||||
return fn(ipv4) |
||||
} |
||||
|
||||
// IPv4Attrs returns a list of attributes supported by the IPv4Addr type
|
||||
func IPv4Attrs() []AttrName { |
||||
return ipv4AddrAttrs |
||||
} |
||||
|
||||
// ipv4AddrInit is called once at init()
|
||||
func ipv4AddrInit() { |
||||
// Sorted for human readability
|
||||
ipv4AddrAttrs = []AttrName{ |
||||
"size", // Same position as in IPv6 for output consistency
|
||||
"broadcast", |
||||
"uint32", |
||||
} |
||||
|
||||
ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{ |
||||
"broadcast": func(ipv4 IPv4Addr) string { |
||||
return ipv4.Broadcast().String() |
||||
}, |
||||
"size": func(ipv4 IPv4Addr) string { |
||||
return fmt.Sprintf("%d", 1<<uint(IPv4len*8-ipv4.Maskbits())) |
||||
}, |
||||
"uint32": func(ipv4 IPv4Addr) string { |
||||
return fmt.Sprintf("%d", uint32(ipv4.Address)) |
||||
}, |
||||
} |
||||
} |
@ -0,0 +1,591 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/binary" |
||||
"fmt" |
||||
"math/big" |
||||
"net" |
||||
) |
||||
|
||||
type ( |
||||
// IPv6Address is a named type representing an IPv6 address.
|
||||
IPv6Address *big.Int |
||||
|
||||
// IPv6Network is a named type representing an IPv6 network.
|
||||
IPv6Network *big.Int |
||||
|
||||
// IPv6Mask is a named type representing an IPv6 network mask.
|
||||
IPv6Mask *big.Int |
||||
) |
||||
|
||||
// IPv6HostPrefix is a constant represents a /128 IPv6 Prefix.
|
||||
const IPv6HostPrefix = IPPrefixLen(128) |
||||
|
||||
// ipv6HostMask is an unexported big.Int representing a /128 IPv6 address.
|
||||
// This value must be a constant and always set to all ones.
|
||||
var ipv6HostMask IPv6Mask |
||||
|
||||
// ipv6AddrAttrMap is a map of the IPv6Addr type-specific attributes.
|
||||
var ipv6AddrAttrMap map[AttrName]func(IPv6Addr) string |
||||
var ipv6AddrAttrs []AttrName |
||||
|
||||
func init() { |
||||
biMask := new(big.Int) |
||||
biMask.SetBytes([]byte{ |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
0xff, 0xff, |
||||
}, |
||||
) |
||||
ipv6HostMask = IPv6Mask(biMask) |
||||
|
||||
ipv6AddrInit() |
||||
} |
||||
|
||||
// IPv6Addr implements a convenience wrapper around the union of Go's
|
||||
// built-in net.IP and net.IPNet types. In UNIX-speak, IPv6Addr implements
|
||||
// `sockaddr` when the the address family is set to AF_INET6
|
||||
// (i.e. `sockaddr_in6`).
|
||||
type IPv6Addr struct { |
||||
IPAddr |
||||
Address IPv6Address |
||||
Mask IPv6Mask |
||||
Port IPPort |
||||
} |
||||
|
||||
// NewIPv6Addr creates an IPv6Addr from a string. String can be in the form of
|
||||
// an an IPv6:port (e.g. `[2001:4860:0:2001::68]:80`, in which case the mask is
|
||||
// assumed to be a /128), an IPv6 address (e.g. `2001:4860:0:2001::68`, also
|
||||
// with a `/128` mask), an IPv6 CIDR (e.g. `2001:4860:0:2001::68/64`, which has
|
||||
// its IP port initialized to zero). ipv6Str can not be a hostname.
|
||||
//
|
||||
// NOTE: Many net.*() routines will initialize and return an IPv4 address.
|
||||
// Always test to make sure the address returned cannot be converted to a 4 byte
|
||||
// array using To4().
|
||||
func NewIPv6Addr(ipv6Str string) (IPv6Addr, error) { |
||||
v6Addr := false |
||||
LOOP: |
||||
for i := 0; i < len(ipv6Str); i++ { |
||||
switch ipv6Str[i] { |
||||
case '.': |
||||
break LOOP |
||||
case ':': |
||||
v6Addr = true |
||||
break LOOP |
||||
} |
||||
} |
||||
|
||||
if !v6Addr { |
||||
return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv6 address, appears to be an IPv4 address", ipv6Str) |
||||
} |
||||
|
||||
// Attempt to parse ipv6Str as a /128 host with a port number.
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp6", ipv6Str) |
||||
if err == nil { |
||||
ipv6 := tcpAddr.IP.To16() |
||||
if ipv6 == nil { |
||||
return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as a 16byte IPv6 address", ipv6Str) |
||||
} |
||||
|
||||
ipv6BigIntAddr := new(big.Int) |
||||
ipv6BigIntAddr.SetBytes(ipv6) |
||||
|
||||
ipv6BigIntMask := new(big.Int) |
||||
ipv6BigIntMask.Set(ipv6HostMask) |
||||
|
||||
ipv6Addr := IPv6Addr{ |
||||
Address: IPv6Address(ipv6BigIntAddr), |
||||
Mask: IPv6Mask(ipv6BigIntMask), |
||||
Port: IPPort(tcpAddr.Port), |
||||
} |
||||
|
||||
return ipv6Addr, nil |
||||
} |
||||
|
||||
// Parse as a naked IPv6 address. Trim square brackets if present.
|
||||
if len(ipv6Str) > 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' { |
||||
ipv6Str = ipv6Str[1 : len(ipv6Str)-1] |
||||
} |
||||
ip := net.ParseIP(ipv6Str) |
||||
if ip != nil { |
||||
ipv6 := ip.To16() |
||||
if ipv6 == nil { |
||||
return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str) |
||||
} |
||||
|
||||
ipv6BigIntAddr := new(big.Int) |
||||
ipv6BigIntAddr.SetBytes(ipv6) |
||||
|
||||
ipv6BigIntMask := new(big.Int) |
||||
ipv6BigIntMask.Set(ipv6HostMask) |
||||
|
||||
return IPv6Addr{ |
||||
Address: IPv6Address(ipv6BigIntAddr), |
||||
Mask: IPv6Mask(ipv6BigIntMask), |
||||
}, nil |
||||
} |
||||
|
||||
// Parse as an IPv6 CIDR
|
||||
ipAddr, network, err := net.ParseCIDR(ipv6Str) |
||||
if err == nil { |
||||
ipv6 := ipAddr.To16() |
||||
if ipv6 == nil { |
||||
return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str) |
||||
} |
||||
|
||||
ipv6BigIntAddr := new(big.Int) |
||||
ipv6BigIntAddr.SetBytes(ipv6) |
||||
|
||||
ipv6BigIntMask := new(big.Int) |
||||
ipv6BigIntMask.SetBytes(network.Mask) |
||||
|
||||
ipv6Addr := IPv6Addr{ |
||||
Address: IPv6Address(ipv6BigIntAddr), |
||||
Mask: IPv6Mask(ipv6BigIntMask), |
||||
} |
||||
return ipv6Addr, nil |
||||
} |
||||
|
||||
return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err) |
||||
} |
||||
|
||||
// AddressBinString returns a string with the IPv6Addr's Address represented
|
||||
// as a sequence of '0' and '1' characters. This method is useful for
|
||||
// debugging or by operators who want to inspect an address.
|
||||
func (ipv6 IPv6Addr) AddressBinString() string { |
||||
bi := big.Int(*ipv6.Address) |
||||
return fmt.Sprintf("%0128s", bi.Text(2)) |
||||
} |
||||
|
||||
// AddressHexString returns a string with the IPv6Addr address represented as
|
||||
// a sequence of hex characters. This method is useful for debugging or by
|
||||
// operators who want to inspect an address.
|
||||
func (ipv6 IPv6Addr) AddressHexString() string { |
||||
bi := big.Int(*ipv6.Address) |
||||
return fmt.Sprintf("%032s", bi.Text(16)) |
||||
} |
||||
|
||||
// CmpAddress follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its address is lower than arg
|
||||
// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a
|
||||
// different type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int { |
||||
ipv6b, ok := sa.(IPv6Addr) |
||||
if !ok { |
||||
return sortDeferDecision |
||||
} |
||||
|
||||
ipv6aBigInt := new(big.Int) |
||||
ipv6aBigInt.Set(ipv6.Address) |
||||
ipv6bBigInt := new(big.Int) |
||||
ipv6bBigInt.Set(ipv6b.Address) |
||||
|
||||
return ipv6aBigInt.Cmp(ipv6bBigInt) |
||||
} |
||||
|
||||
// CmpPort follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its port is lower than arg
|
||||
// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr,
|
||||
// regardless of type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int { |
||||
var saPort IPPort |
||||
switch v := sa.(type) { |
||||
case IPv4Addr: |
||||
saPort = v.Port |
||||
case IPv6Addr: |
||||
saPort = v.Port |
||||
default: |
||||
return sortDeferDecision |
||||
} |
||||
|
||||
switch { |
||||
case ipv6.Port == saPort: |
||||
return sortDeferDecision |
||||
case ipv6.Port < saPort: |
||||
return sortReceiverBeforeArg |
||||
default: |
||||
return sortArgBeforeReceiver |
||||
} |
||||
} |
||||
|
||||
// CmpRFC follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because it belongs to the RFC and its
|
||||
// arg does not
|
||||
// - 0 if the receiver and arg both belong to the same RFC or neither do.
|
||||
// - 1 If the arg belongs to the RFC but receiver does not.
|
||||
func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int { |
||||
recvInRFC := IsRFC(rfcNum, ipv6) |
||||
ipv6b, ok := sa.(IPv6Addr) |
||||
if !ok { |
||||
// If the receiver is part of the desired RFC and the SockAddr
|
||||
// argument is not, sort receiver before the non-IPv6 SockAddr.
|
||||
// Conversely, if the receiver is not part of the RFC, punt on
|
||||
// sorting and leave it for the next sorter.
|
||||
if recvInRFC { |
||||
return sortReceiverBeforeArg |
||||
} else { |
||||
return sortDeferDecision |
||||
} |
||||
} |
||||
|
||||
argInRFC := IsRFC(rfcNum, ipv6b) |
||||
switch { |
||||
case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC): |
||||
// If a and b both belong to the RFC, or neither belong to
|
||||
// rfcNum, defer sorting to the next sorter.
|
||||
return sortDeferDecision |
||||
case recvInRFC && !argInRFC: |
||||
return sortReceiverBeforeArg |
||||
default: |
||||
return sortArgBeforeReceiver |
||||
} |
||||
} |
||||
|
||||
// Contains returns true if the SockAddr is contained within the receiver.
|
||||
func (ipv6 IPv6Addr) Contains(sa SockAddr) bool { |
||||
ipv6b, ok := sa.(IPv6Addr) |
||||
if !ok { |
||||
return false |
||||
} |
||||
|
||||
return ipv6.ContainsNetwork(ipv6b) |
||||
} |
||||
|
||||
// ContainsAddress returns true if the IPv6Address is contained within the
|
||||
// receiver.
|
||||
func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool { |
||||
xAddr := IPv6Addr{ |
||||
Address: x, |
||||
Mask: ipv6HostMask, |
||||
} |
||||
|
||||
{ |
||||
xIPv6 := xAddr.FirstUsable().(IPv6Addr) |
||||
yIPv6 := ipv6.FirstUsable().(IPv6Addr) |
||||
if xIPv6.CmpAddress(yIPv6) >= 1 { |
||||
return false |
||||
} |
||||
} |
||||
|
||||
{ |
||||
xIPv6 := xAddr.LastUsable().(IPv6Addr) |
||||
yIPv6 := ipv6.LastUsable().(IPv6Addr) |
||||
if xIPv6.CmpAddress(yIPv6) <= -1 { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// ContainsNetwork returns true if the network from IPv6Addr is contained within
|
||||
// the receiver.
|
||||
func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool { |
||||
{ |
||||
xIPv6 := x.FirstUsable().(IPv6Addr) |
||||
yIPv6 := y.FirstUsable().(IPv6Addr) |
||||
if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 { |
||||
return false |
||||
} |
||||
} |
||||
|
||||
{ |
||||
xIPv6 := x.LastUsable().(IPv6Addr) |
||||
yIPv6 := y.LastUsable().(IPv6Addr) |
||||
if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// DialPacketArgs returns the arguments required to be passed to
|
||||
// net.DialUDP(). If the Mask of ipv6 is not a /128 or the Port is 0,
|
||||
// DialPacketArgs() will fail. See Host() to create an IPv6Addr with its
|
||||
// mask set to /128.
|
||||
func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) { |
||||
ipv6Mask := big.Int(*ipv6.Mask) |
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 { |
||||
return "udp6", "" |
||||
} |
||||
return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) |
||||
} |
||||
|
||||
// DialStreamArgs returns the arguments required to be passed to
|
||||
// net.DialTCP(). If the Mask of ipv6 is not a /128 or the Port is 0,
|
||||
// DialStreamArgs() will fail. See Host() to create an IPv6Addr with its
|
||||
// mask set to /128.
|
||||
func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) { |
||||
ipv6Mask := big.Int(*ipv6.Mask) |
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 { |
||||
return "tcp6", "" |
||||
} |
||||
return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) |
||||
} |
||||
|
||||
// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
|
||||
func (ipv6a IPv6Addr) Equal(sa SockAddr) bool { |
||||
ipv6b, ok := sa.(IPv6Addr) |
||||
if !ok { |
||||
return false |
||||
} |
||||
|
||||
if ipv6a.NetIP().String() != ipv6b.NetIP().String() { |
||||
return false |
||||
} |
||||
|
||||
if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() { |
||||
return false |
||||
} |
||||
|
||||
if ipv6a.Port != ipv6b.Port { |
||||
return false |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
// FirstUsable returns an IPv6Addr set to the first address following the
|
||||
// network prefix. The first usable address in a network is normally the
|
||||
// gateway and should not be used except by devices forwarding packets
|
||||
// between two administratively distinct networks (i.e. a router). This
|
||||
// function does not discriminate against first usable vs "first address that
|
||||
// should be used." For example, FirstUsable() on "2001:0db8::0003/64" would
|
||||
// return "2001:0db8::00011".
|
||||
func (ipv6 IPv6Addr) FirstUsable() IPAddr { |
||||
return IPv6Addr{ |
||||
Address: IPv6Address(ipv6.NetworkAddress()), |
||||
Mask: ipv6HostMask, |
||||
} |
||||
} |
||||
|
||||
// Host returns a copy of ipv6 with its mask set to /128 so that it can be
|
||||
// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
|
||||
// ListenStreamArgs().
|
||||
func (ipv6 IPv6Addr) Host() IPAddr { |
||||
// Nothing should listen on a broadcast address.
|
||||
return IPv6Addr{ |
||||
Address: ipv6.Address, |
||||
Mask: ipv6HostMask, |
||||
Port: ipv6.Port, |
||||
} |
||||
} |
||||
|
||||
// IPPort returns the Port number attached to the IPv6Addr
|
||||
func (ipv6 IPv6Addr) IPPort() IPPort { |
||||
return ipv6.Port |
||||
} |
||||
|
||||
// LastUsable returns the last address in a given network.
|
||||
func (ipv6 IPv6Addr) LastUsable() IPAddr { |
||||
addr := new(big.Int) |
||||
addr.Set(ipv6.Address) |
||||
|
||||
mask := new(big.Int) |
||||
mask.Set(ipv6.Mask) |
||||
|
||||
negMask := new(big.Int) |
||||
negMask.Xor(ipv6HostMask, mask) |
||||
|
||||
lastAddr := new(big.Int) |
||||
lastAddr.And(addr, mask) |
||||
lastAddr.Or(lastAddr, negMask) |
||||
|
||||
return IPv6Addr{ |
||||
Address: IPv6Address(lastAddr), |
||||
Mask: ipv6HostMask, |
||||
} |
||||
} |
||||
|
||||
// ListenPacketArgs returns the arguments required to be passed to
|
||||
// net.ListenUDP(). If the Mask of ipv6 is not a /128, ListenPacketArgs()
|
||||
// will fail. See Host() to create an IPv6Addr with its mask set to /128.
|
||||
func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) { |
||||
ipv6Mask := big.Int(*ipv6.Mask) |
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 { |
||||
return "udp6", "" |
||||
} |
||||
return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) |
||||
} |
||||
|
||||
// ListenStreamArgs returns the arguments required to be passed to
|
||||
// net.ListenTCP(). If the Mask of ipv6 is not a /128, ListenStreamArgs()
|
||||
// will fail. See Host() to create an IPv6Addr with its mask set to /128.
|
||||
func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) { |
||||
ipv6Mask := big.Int(*ipv6.Mask) |
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 { |
||||
return "tcp6", "" |
||||
} |
||||
return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) |
||||
} |
||||
|
||||
// Maskbits returns the number of network mask bits in a given IPv6Addr. For
|
||||
// example, the Maskbits() of "2001:0db8::0003/64" would return 64.
|
||||
func (ipv6 IPv6Addr) Maskbits() int { |
||||
maskOnes, _ := ipv6.NetIPNet().Mask.Size() |
||||
|
||||
return maskOnes |
||||
} |
||||
|
||||
// MustIPv6Addr is a helper method that must return an IPv6Addr or panic on
|
||||
// invalid input.
|
||||
func MustIPv6Addr(addr string) IPv6Addr { |
||||
ipv6, err := NewIPv6Addr(addr) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err)) |
||||
} |
||||
return ipv6 |
||||
} |
||||
|
||||
// NetIP returns the address as a net.IP.
|
||||
func (ipv6 IPv6Addr) NetIP() *net.IP { |
||||
return bigIntToNetIPv6(ipv6.Address) |
||||
} |
||||
|
||||
// NetIPMask create a new net.IPMask from the IPv6Addr.
|
||||
func (ipv6 IPv6Addr) NetIPMask() *net.IPMask { |
||||
ipv6Mask := make(net.IPMask, IPv6len) |
||||
m := big.Int(*ipv6.Mask) |
||||
copy(ipv6Mask, m.Bytes()) |
||||
return &ipv6Mask |
||||
} |
||||
|
||||
// Network returns a pointer to the net.IPNet within IPv4Addr receiver.
|
||||
func (ipv6 IPv6Addr) NetIPNet() *net.IPNet { |
||||
ipv6net := &net.IPNet{} |
||||
ipv6net.IP = make(net.IP, IPv6len) |
||||
copy(ipv6net.IP, *ipv6.NetIP()) |
||||
ipv6net.Mask = *ipv6.NetIPMask() |
||||
return ipv6net |
||||
} |
||||
|
||||
// Network returns the network prefix or network address for a given network.
|
||||
func (ipv6 IPv6Addr) Network() IPAddr { |
||||
return IPv6Addr{ |
||||
Address: IPv6Address(ipv6.NetworkAddress()), |
||||
Mask: ipv6.Mask, |
||||
} |
||||
} |
||||
|
||||
// NetworkAddress returns an IPv6Network of the IPv6Addr's network address.
|
||||
func (ipv6 IPv6Addr) NetworkAddress() IPv6Network { |
||||
addr := new(big.Int) |
||||
addr.SetBytes((*ipv6.Address).Bytes()) |
||||
|
||||
mask := new(big.Int) |
||||
mask.SetBytes(*ipv6.NetIPMask()) |
||||
|
||||
netAddr := new(big.Int) |
||||
netAddr.And(addr, mask) |
||||
|
||||
return IPv6Network(netAddr) |
||||
} |
||||
|
||||
// Octets returns a slice of the 16 octets in an IPv6Addr's Address. The
|
||||
// order of the bytes is big endian.
|
||||
func (ipv6 IPv6Addr) Octets() []int { |
||||
x := make([]int, IPv6len) |
||||
for i, b := range *bigIntToNetIPv6(ipv6.Address) { |
||||
x[i] = int(b) |
||||
} |
||||
|
||||
return x |
||||
} |
||||
|
||||
// String returns a string representation of the IPv6Addr
|
||||
func (ipv6 IPv6Addr) String() string { |
||||
if ipv6.Port != 0 { |
||||
return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) |
||||
} |
||||
|
||||
if ipv6.Maskbits() == 128 { |
||||
return ipv6.NetIP().String() |
||||
} |
||||
|
||||
return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits()) |
||||
} |
||||
|
||||
// Type is used as a type switch and returns TypeIPv6
|
||||
func (IPv6Addr) Type() SockAddrType { |
||||
return TypeIPv6 |
||||
} |
||||
|
||||
// IPv6Attrs returns a list of attributes supported by the IPv6Addr type
|
||||
func IPv6Attrs() []AttrName { |
||||
return ipv6AddrAttrs |
||||
} |
||||
|
||||
// IPv6AddrAttr returns a string representation of an attribute for the given
|
||||
// IPv6Addr.
|
||||
func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string { |
||||
fn, found := ipv6AddrAttrMap[selector] |
||||
if !found { |
||||
return "" |
||||
} |
||||
|
||||
return fn(ipv6) |
||||
} |
||||
|
||||
// ipv6AddrInit is called once at init()
|
||||
func ipv6AddrInit() { |
||||
// Sorted for human readability
|
||||
ipv6AddrAttrs = []AttrName{ |
||||
"size", // Same position as in IPv6 for output consistency
|
||||
"uint128", |
||||
} |
||||
|
||||
ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{ |
||||
"size": func(ipv6 IPv6Addr) string { |
||||
netSize := big.NewInt(1) |
||||
netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits())) |
||||
return netSize.Text(10) |
||||
}, |
||||
"uint128": func(ipv6 IPv6Addr) string { |
||||
b := big.Int(*ipv6.Address) |
||||
return b.Text(10) |
||||
}, |
||||
} |
||||
} |
||||
|
||||
// bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the
|
||||
// correctly padded values.
|
||||
func bigIntToNetIPv6(bi *big.Int) *net.IP { |
||||
x := make(net.IP, IPv6len) |
||||
ipv6Bytes := bi.Bytes() |
||||
|
||||
// It's possibe for ipv6Bytes to be less than IPv6len bytes in size. If
|
||||
// they are different sizes we to pad the size of response.
|
||||
if len(ipv6Bytes) < IPv6len { |
||||
buf := new(bytes.Buffer) |
||||
buf.Grow(IPv6len) |
||||
|
||||
for i := len(ipv6Bytes); i < IPv6len; i++ { |
||||
if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil { |
||||
panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err)) |
||||
} |
||||
} |
||||
|
||||
for _, b := range ipv6Bytes { |
||||
if err := binary.Write(buf, binary.BigEndian, b); err != nil { |
||||
panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err)) |
||||
} |
||||
} |
||||
|
||||
ipv6Bytes = buf.Bytes() |
||||
} |
||||
i := copy(x, ipv6Bytes) |
||||
if i != IPv6len { |
||||
panic("IPv6 wrong size") |
||||
} |
||||
return &x |
||||
} |
@ -0,0 +1,947 @@
|
||||
package sockaddr |
||||
|
||||
// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP
|
||||
// blocks.
|
||||
const ForwardingBlacklist = 4294967295 |
||||
|
||||
// IsRFC tests to see if an SockAddr matches the specified RFC
|
||||
func IsRFC(rfcNum uint, sa SockAddr) bool { |
||||
rfcNetMap := KnownRFCs() |
||||
rfcNets, ok := rfcNetMap[rfcNum] |
||||
if !ok { |
||||
return false |
||||
} |
||||
|
||||
var contained bool |
||||
for _, rfcNet := range rfcNets { |
||||
if rfcNet.Contains(sa) { |
||||
contained = true |
||||
break |
||||
} |
||||
} |
||||
return contained |
||||
} |
||||
|
||||
// KnownRFCs returns an initial set of known RFCs.
|
||||
//
|
||||
// NOTE (sean@): As this list evolves over time, please submit patches to keep
|
||||
// this list current. If something isn't right, inquire, as it may just be a
|
||||
// bug on my part. Some of the inclusions were based on my judgement as to what
|
||||
// would be a useful value (e.g. RFC3330).
|
||||
//
|
||||
// Useful resources:
|
||||
//
|
||||
// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
|
||||
// * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml
|
||||
// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
|
||||
func KnownRFCs() map[uint]SockAddrs { |
||||
// NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a
|
||||
// RADIX tree, but `ENOTIME`. Patches welcome.
|
||||
return map[uint]SockAddrs{ |
||||
919: SockAddrs{ |
||||
// [RFC919] Broadcasting Internet Datagrams
|
||||
MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards
|
||||
}, |
||||
1122: SockAddrs{ |
||||
// [RFC1122] Requirements for Internet Hosts -- Communication Layers
|
||||
MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3
|
||||
MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3
|
||||
}, |
||||
1112: SockAddrs{ |
||||
// [RFC1112] Host Extensions for IP Multicasting
|
||||
MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses
|
||||
}, |
||||
1918: SockAddrs{ |
||||
// [RFC1918] Address Allocation for Private Internets
|
||||
MustIPv4Addr("10.0.0.0/8"), |
||||
MustIPv4Addr("172.16.0.0/12"), |
||||
MustIPv4Addr("192.168.0.0/16"), |
||||
}, |
||||
2544: SockAddrs{ |
||||
// [RFC2544] Benchmarking Methodology for Network
|
||||
// Interconnect Devices
|
||||
MustIPv4Addr("198.18.0.0/15"), |
||||
}, |
||||
2765: SockAddrs{ |
||||
// [RFC2765] Stateless IP/ICMP Translation Algorithm
|
||||
// (SIIT) (obsoleted by RFCs 6145, which itself was
|
||||
// later obsoleted by 7915).
|
||||
|
||||
// [RFC2765], §2.1 Addresses
|
||||
MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"), |
||||
}, |
||||
2928: SockAddrs{ |
||||
// [RFC2928] Initial IPv6 Sub-TLA ID Assignments
|
||||
MustIPv6Addr("2001::/16"), // Superblock
|
||||
//MustIPv6Addr("2001:0000::/23"), // IANA
|
||||
//MustIPv6Addr("2001:0200::/23"), // APNIC
|
||||
//MustIPv6Addr("2001:0400::/23"), // ARIN
|
||||
//MustIPv6Addr("2001:0600::/23"), // RIPE NCC
|
||||
//MustIPv6Addr("2001:0800::/23"), // (future assignment)
|
||||
// ...
|
||||
//MustIPv6Addr("2001:FE00::/23"), // (future assignment)
|
||||
}, |
||||
3056: SockAddrs{ // 6to4 address
|
||||
// [RFC3056] Connection of IPv6 Domains via IPv4 Clouds
|
||||
|
||||
// [RFC3056], §2 IPv6 Prefix Allocation
|
||||
MustIPv6Addr("2002::/16"), |
||||
}, |
||||
3068: SockAddrs{ |
||||
// [RFC3068] An Anycast Prefix for 6to4 Relay Routers
|
||||
// (obsolete by RFC7526)
|
||||
|
||||
// [RFC3068], § 6to4 Relay anycast address
|
||||
MustIPv4Addr("192.88.99.0/24"), |
||||
|
||||
// [RFC3068], §2.5 6to4 IPv6 relay anycast address
|
||||
//
|
||||
// NOTE: /120 == 128-(32-24)
|
||||
MustIPv6Addr("2002:c058:6301::/120"), |
||||
}, |
||||
3171: SockAddrs{ |
||||
// [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments
|
||||
MustIPv4Addr("224.0.0.0/4"), |
||||
}, |
||||
3330: SockAddrs{ |
||||
// [RFC3330] Special-Use IPv4 Addresses
|
||||
|
||||
// Addresses in this block refer to source hosts on
|
||||
// "this" network. Address 0.0.0.0/32 may be used as a
|
||||
// source address for this host on this network; other
|
||||
// addresses within 0.0.0.0/8 may be used to refer to
|
||||
// specified hosts on this network [RFC1700, page 4].
|
||||
MustIPv4Addr("0.0.0.0/8"), |
||||
|
||||
// 10.0.0.0/8 - This block is set aside for use in
|
||||
// private networks. Its intended use is documented in
|
||||
// [RFC1918]. Addresses within this block should not
|
||||
// appear on the public Internet.
|
||||
MustIPv4Addr("10.0.0.0/8"), |
||||
|
||||
// 14.0.0.0/8 - This block is set aside for assignments
|
||||
// to the international system of Public Data Networks
|
||||
// [RFC1700, page 181]. The registry of assignments
|
||||
// within this block can be accessed from the "Public
|
||||
// Data Network Numbers" link on the web page at
|
||||
// http://www.iana.org/numbers.html. Addresses within
|
||||
// this block are assigned to users and should be
|
||||
// treated as such.
|
||||
|
||||
// 24.0.0.0/8 - This block was allocated in early 1996
|
||||
// for use in provisioning IP service over cable
|
||||
// television systems. Although the IANA initially was
|
||||
// involved in making assignments to cable operators,
|
||||
// this responsibility was transferred to American
|
||||
// Registry for Internet Numbers (ARIN) in May 2001.
|
||||
// Addresses within this block are assigned in the
|
||||
// normal manner and should be treated as such.
|
||||
|
||||
// 39.0.0.0/8 - This block was used in the "Class A
|
||||
// Subnet Experiment" that commenced in May 1995, as
|
||||
// documented in [RFC1797]. The experiment has been
|
||||
// completed and this block has been returned to the
|
||||
// pool of addresses reserved for future allocation or
|
||||
// assignment. This block therefore no longer has a
|
||||
// special use and is subject to allocation to a
|
||||
// Regional Internet Registry for assignment in the
|
||||
// normal manner.
|
||||
|
||||
// 127.0.0.0/8 - This block is assigned for use as the Internet host
|
||||
// loopback address. A datagram sent by a higher level protocol to an
|
||||
// address anywhere within this block should loop back inside the host.
|
||||
// This is ordinarily implemented using only 127.0.0.1/32 for loopback,
|
||||
// but no addresses within this block should ever appear on any network
|
||||
// anywhere [RFC1700, page 5].
|
||||
MustIPv4Addr("127.0.0.0/8"), |
||||
|
||||
// 128.0.0.0/16 - This block, corresponding to the
|
||||
// numerically lowest of the former Class B addresses,
|
||||
// was initially and is still reserved by the IANA.
|
||||
// Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer
|
||||
// applies and addresses in this block are subject to
|
||||
// future allocation to a Regional Internet Registry for
|
||||
// assignment in the normal manner.
|
||||
|
||||
// 169.254.0.0/16 - This is the "link local" block. It
|
||||
// is allocated for communication between hosts on a
|
||||
// single link. Hosts obtain these addresses by
|
||||
// auto-configuration, such as when a DHCP server may
|
||||
// not be found.
|
||||
MustIPv4Addr("169.254.0.0/16"), |
||||
|
||||
// 172.16.0.0/12 - This block is set aside for use in
|
||||
// private networks. Its intended use is documented in
|
||||
// [RFC1918]. Addresses within this block should not
|
||||
// appear on the public Internet.
|
||||
MustIPv4Addr("172.16.0.0/12"), |
||||
|
||||
// 191.255.0.0/16 - This block, corresponding to the numerically highest
|
||||
// to the former Class B addresses, was initially and is still reserved
|
||||
// by the IANA. Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer applies and addresses
|
||||
// in this block are subject to future allocation to a Regional Internet
|
||||
// Registry for assignment in the normal manner.
|
||||
|
||||
// 192.0.0.0/24 - This block, corresponding to the
|
||||
// numerically lowest of the former Class C addresses,
|
||||
// was initially and is still reserved by the IANA.
|
||||
// Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer
|
||||
// applies and addresses in this block are subject to
|
||||
// future allocation to a Regional Internet Registry for
|
||||
// assignment in the normal manner.
|
||||
|
||||
// 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in
|
||||
// documentation and example code. It is often used in conjunction with
|
||||
// domain names example.com or example.net in vendor and protocol
|
||||
// documentation. Addresses within this block should not appear on the
|
||||
// public Internet.
|
||||
MustIPv4Addr("192.0.2.0/24"), |
||||
|
||||
// 192.88.99.0/24 - This block is allocated for use as 6to4 relay
|
||||
// anycast addresses, according to [RFC3068].
|
||||
MustIPv4Addr("192.88.99.0/24"), |
||||
|
||||
// 192.168.0.0/16 - This block is set aside for use in private networks.
|
||||
// Its intended use is documented in [RFC1918]. Addresses within this
|
||||
// block should not appear on the public Internet.
|
||||
MustIPv4Addr("192.168.0.0/16"), |
||||
|
||||
// 198.18.0.0/15 - This block has been allocated for use
|
||||
// in benchmark tests of network interconnect devices.
|
||||
// Its use is documented in [RFC2544].
|
||||
MustIPv4Addr("198.18.0.0/15"), |
||||
|
||||
// 223.255.255.0/24 - This block, corresponding to the
|
||||
// numerically highest of the former Class C addresses,
|
||||
// was initially and is still reserved by the IANA.
|
||||
// Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer
|
||||
// applies and addresses in this block are subject to
|
||||
// future allocation to a Regional Internet Registry for
|
||||
// assignment in the normal manner.
|
||||
|
||||
// 224.0.0.0/4 - This block, formerly known as the Class
|
||||
// D address space, is allocated for use in IPv4
|
||||
// multicast address assignments. The IANA guidelines
|
||||
// for assignments from this space are described in
|
||||
// [RFC3171].
|
||||
MustIPv4Addr("224.0.0.0/4"), |
||||
|
||||
// 240.0.0.0/4 - This block, formerly known as the Class E address
|
||||
// space, is reserved. The "limited broadcast" destination address
|
||||
// 255.255.255.255 should never be forwarded outside the (sub-)net of
|
||||
// the source. The remainder of this space is reserved
|
||||
// for future use. [RFC1700, page 4]
|
||||
MustIPv4Addr("240.0.0.0/4"), |
||||
}, |
||||
3849: SockAddrs{ |
||||
// [RFC3849] IPv6 Address Prefix Reserved for Documentation
|
||||
MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations
|
||||
}, |
||||
3927: SockAddrs{ |
||||
// [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses
|
||||
MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection
|
||||
}, |
||||
4038: SockAddrs{ |
||||
// [RFC4038] Application Aspects of IPv6 Transition
|
||||
|
||||
// [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node
|
||||
MustIPv6Addr("0:0:0:0:0:ffff::/96"), |
||||
}, |
||||
4193: SockAddrs{ |
||||
// [RFC4193] Unique Local IPv6 Unicast Addresses
|
||||
MustIPv6Addr("fc00::/7"), |
||||
}, |
||||
4291: SockAddrs{ |
||||
// [RFC4291] IP Version 6 Addressing Architecture
|
||||
|
||||
// [RFC4291], §2.5.2 The Unspecified Address
|
||||
MustIPv6Addr("::/128"), |
||||
|
||||
// [RFC4291], §2.5.3 The Loopback Address
|
||||
MustIPv6Addr("::1/128"), |
||||
|
||||
// [RFC4291], §2.5.5.1. IPv4-Compatible IPv6 Address
|
||||
MustIPv6Addr("::/96"), |
||||
|
||||
// [RFC4291], §2.5.5.2. IPv4-Mapped IPv6 Address
|
||||
MustIPv6Addr("::ffff:0:0/96"), |
||||
|
||||
// [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses
|
||||
MustIPv6Addr("fe80::/10"), |
||||
|
||||
// [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses
|
||||
// (depreciated)
|
||||
MustIPv6Addr("fec0::/10"), |
||||
|
||||
// [RFC4291], §2.7 Multicast Addresses
|
||||
MustIPv6Addr("ff00::/8"), |
||||
|
||||
// IPv6 Multicast Information.
|
||||
//
|
||||
// In the following "table" below, `ff0x` is replaced
|
||||
// with the following values depending on the scope of
|
||||
// the query:
|
||||
//
|
||||
// IPv6 Multicast Scopes:
|
||||
// * ff00/9 // reserved
|
||||
// * ff01/9 // interface-local
|
||||
// * ff02/9 // link-local
|
||||
// * ff03/9 // realm-local
|
||||
// * ff04/9 // admin-local
|
||||
// * ff05/9 // site-local
|
||||
// * ff08/9 // organization-local
|
||||
// * ff0e/9 // global
|
||||
// * ff0f/9 // reserved
|
||||
//
|
||||
// IPv6 Multicast Addresses:
|
||||
// * ff0x::2 // All routers
|
||||
// * ff02::5 // OSPFIGP
|
||||
// * ff02::6 // OSPFIGP Designated Routers
|
||||
// * ff02::9 // RIP Routers
|
||||
// * ff02::a // EIGRP Routers
|
||||
// * ff02::d // All PIM Routers
|
||||
// * ff02::1a // All RPL Routers
|
||||
// * ff0x::fb // mDNSv6
|
||||
// * ff0x::101 // All Network Time Protocol (NTP) servers
|
||||
// * ff02::1:1 // Link Name
|
||||
// * ff02::1:2 // All-dhcp-agents
|
||||
// * ff02::1:3 // Link-local Multicast Name Resolution
|
||||
// * ff05::1:3 // All-dhcp-servers
|
||||
// * ff02::1:ff00:0/104 // Solicited-node multicast address.
|
||||
// * ff02::2:ff00:0/104 // Node Information Queries
|
||||
}, |
||||
4380: SockAddrs{ |
||||
// [RFC4380] Teredo: Tunneling IPv6 over UDP through
|
||||
// Network Address Translations (NATs)
|
||||
|
||||
// [RFC4380], §2.6 Global Teredo IPv6 Service Prefix
|
||||
MustIPv6Addr("2001:0000::/32"), |
||||
}, |
||||
4773: SockAddrs{ |
||||
// [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block
|
||||
MustIPv6Addr("2001:0000::/23"), // IANA
|
||||
}, |
||||
4843: SockAddrs{ |
||||
// [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID)
|
||||
MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations
|
||||
}, |
||||
5180: SockAddrs{ |
||||
// [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices
|
||||
MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations
|
||||
}, |
||||
5735: SockAddrs{ |
||||
// [RFC5735] Special Use IPv4 Addresses
|
||||
MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
|
||||
MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
|
||||
MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
|
||||
MustIPv4Addr("198.18.0.0/15"), // Benchmarks
|
||||
}, |
||||
5737: SockAddrs{ |
||||
// [RFC5737] IPv4 Address Blocks Reserved for Documentation
|
||||
MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
|
||||
MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
|
||||
MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
|
||||
}, |
||||
6052: SockAddrs{ |
||||
// [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators
|
||||
MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix
|
||||
}, |
||||
6333: SockAddrs{ |
||||
// [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion
|
||||
MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address
|
||||
}, |
||||
6598: SockAddrs{ |
||||
// [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space
|
||||
MustIPv4Addr("100.64.0.0/10"), |
||||
}, |
||||
6666: SockAddrs{ |
||||
// [RFC6666] A Discard Prefix for IPv6
|
||||
MustIPv6Addr("0100::/64"), |
||||
}, |
||||
6890: SockAddrs{ |
||||
// [RFC6890] Special-Purpose IP Address Registries
|
||||
|
||||
// From "RFC6890 §2.2.1 Information Requirements":
|
||||
/* |
||||
The IPv4 and IPv6 Special-Purpose Address Registries maintain the |
||||
following information regarding each entry: |
||||
|
||||
o Address Block - A block of IPv4 or IPv6 addresses that has been |
||||
registered for a special purpose. |
||||
|
||||
o Name - A descriptive name for the special-purpose address block. |
||||
|
||||
o RFC - The RFC through which the special-purpose address block was |
||||
requested. |
||||
|
||||
o Allocation Date - The date upon which the special-purpose address |
||||
block was allocated. |
||||
|
||||
o Termination Date - The date upon which the allocation is to be |
||||
terminated. This field is applicable for limited-use allocations |
||||
only. |
||||
|
||||
o Source - A boolean value indicating whether an address from the |
||||
allocated special-purpose address block is valid when used as the |
||||
source address of an IP datagram that transits two devices. |
||||
|
||||
o Destination - A boolean value indicating whether an address from |
||||
the allocated special-purpose address block is valid when used as |
||||
the destination address of an IP datagram that transits two |
||||
devices. |
||||
|
||||
o Forwardable - A boolean value indicating whether a router may |
||||
forward an IP datagram whose destination address is drawn from the |
||||
allocated special-purpose address block between external |
||||
interfaces. |
||||
|
||||
o Global - A boolean value indicating whether an IP datagram whose |
||||
destination address is drawn from the allocated special-purpose |
||||
address block is forwardable beyond a specified administrative |
||||
domain. |
||||
|
||||
o Reserved-by-Protocol - A boolean value indicating whether the |
||||
special-purpose address block is reserved by IP, itself. This |
||||
value is "TRUE" if the RFC that created the special-purpose |
||||
address block requires all compliant IP implementations to behave |
||||
in a special way when processing packets either to or from |
||||
addresses contained by the address block. |
||||
|
||||
If the value of "Destination" is FALSE, the values of "Forwardable" |
||||
and "Global" must also be false. |
||||
*/ |
||||
|
||||
/*+----------------------+----------------------------+ |
||||
* | Attribute | Value | |
||||
* +----------------------+----------------------------+ |
||||
* | Address Block | 0.0.0.0/8 | |
||||
* | Name | "This host on this network"| |
||||
* | RFC | [RFC1122], Section 3.2.1.3 | |
||||
* | Allocation Date | September 1981 | |
||||
* | Termination Date | N/A | |
||||
* | Source | True | |
||||
* | Destination | False | |
||||
* | Forwardable | False | |
||||
* | Global | False | |
||||
* | Reserved-by-Protocol | True | |
||||
* +----------------------+----------------------------+*/ |
||||
MustIPv4Addr("0.0.0.0/8"), |
||||
|
||||
/*+----------------------+---------------+ |
||||
* | Attribute | Value | |
||||
* +----------------------+---------------+ |
||||
* | Address Block | 10.0.0.0/8 | |
||||
* | Name | Private-Use | |
||||
* | RFC | [RFC1918] | |
||||
* | Allocation Date | February 1996 | |
||||
* | Termination Date | N/A | |
||||
* | Source | True | |
||||
* | Destination | True | |
||||
* | Forwardable | True | |
||||
* | Global | False | |
||||
* | Reserved-by-Protocol | False | |
||||
* +----------------------+---------------+ */ |
||||
MustIPv4Addr("10.0.0.0/8"), |
||||
|
||||
/*+----------------------+----------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------+ |
||||
| Address Block | 100.64.0.0/10 | |
||||
| Name | Shared Address Space | |
||||
| RFC | [RFC6598] | |
||||
| Allocation Date | April 2012 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------------+*/ |
||||
MustIPv4Addr("100.64.0.0/10"), |
||||
|
||||
/*+----------------------+----------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------------+ |
||||
| Address Block | 127.0.0.0/8 | |
||||
| Name | Loopback | |
||||
| RFC | [RFC1122], Section 3.2.1.3 | |
||||
| Allocation Date | September 1981 | |
||||
| Termination Date | N/A | |
||||
| Source | False [1] | |
||||
| Destination | False [1] | |
||||
| Forwardable | False [1] | |
||||
| Global | False [1] | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+----------------------------+*/ |
||||
// [1] Several protocols have been granted exceptions to
|
||||
// this rule. For examples, see [RFC4379] and
|
||||
// [RFC5884].
|
||||
MustIPv4Addr("127.0.0.0/8"), |
||||
|
||||
/*+----------------------+----------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------+ |
||||
| Address Block | 169.254.0.0/16 | |
||||
| Name | Link Local | |
||||
| RFC | [RFC3927] | |
||||
| Allocation Date | May 2005 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+----------------+*/ |
||||
MustIPv4Addr("169.254.0.0/16"), |
||||
|
||||
/*+----------------------+---------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------+ |
||||
| Address Block | 172.16.0.0/12 | |
||||
| Name | Private-Use | |
||||
| RFC | [RFC1918] | |
||||
| Allocation Date | February 1996 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------+*/ |
||||
MustIPv4Addr("172.16.0.0/12"), |
||||
|
||||
/*+----------------------+---------------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------------------------+ |
||||
| Address Block | 192.0.0.0/24 [2] | |
||||
| Name | IETF Protocol Assignments | |
||||
| RFC | Section 2.1 of this document | |
||||
| Allocation Date | January 2010 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------------------------+*/ |
||||
// [2] Not usable unless by virtue of a more specific
|
||||
// reservation.
|
||||
MustIPv4Addr("192.0.0.0/24"), |
||||
|
||||
/*+----------------------+--------------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+--------------------------------+ |
||||
| Address Block | 192.0.0.0/29 | |
||||
| Name | IPv4 Service Continuity Prefix | |
||||
| RFC | [RFC6333], [RFC7335] | |
||||
| Allocation Date | June 2011 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+--------------------------------+*/ |
||||
MustIPv4Addr("192.0.0.0/29"), |
||||
|
||||
/*+----------------------+----------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------------+ |
||||
| Address Block | 192.0.2.0/24 | |
||||
| Name | Documentation (TEST-NET-1) | |
||||
| RFC | [RFC5737] | |
||||
| Allocation Date | January 2010 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------------------+*/ |
||||
MustIPv4Addr("192.0.2.0/24"), |
||||
|
||||
/*+----------------------+--------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+--------------------+ |
||||
| Address Block | 192.88.99.0/24 | |
||||
| Name | 6to4 Relay Anycast | |
||||
| RFC | [RFC3068] | |
||||
| Allocation Date | June 2001 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | True | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+--------------------+*/ |
||||
MustIPv4Addr("192.88.99.0/24"), |
||||
|
||||
/*+----------------------+----------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------+ |
||||
| Address Block | 192.168.0.0/16 | |
||||
| Name | Private-Use | |
||||
| RFC | [RFC1918] | |
||||
| Allocation Date | February 1996 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------+*/ |
||||
MustIPv4Addr("192.168.0.0/16"), |
||||
|
||||
/*+----------------------+---------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------+ |
||||
| Address Block | 198.18.0.0/15 | |
||||
| Name | Benchmarking | |
||||
| RFC | [RFC2544] | |
||||
| Allocation Date | March 1999 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------+*/ |
||||
MustIPv4Addr("198.18.0.0/15"), |
||||
|
||||
/*+----------------------+----------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------------+ |
||||
| Address Block | 198.51.100.0/24 | |
||||
| Name | Documentation (TEST-NET-2) | |
||||
| RFC | [RFC5737] | |
||||
| Allocation Date | January 2010 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------------------+*/ |
||||
MustIPv4Addr("198.51.100.0/24"), |
||||
|
||||
/*+----------------------+----------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------------+ |
||||
| Address Block | 203.0.113.0/24 | |
||||
| Name | Documentation (TEST-NET-3) | |
||||
| RFC | [RFC5737] | |
||||
| Allocation Date | January 2010 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------------------+*/ |
||||
MustIPv4Addr("203.0.113.0/24"), |
||||
|
||||
/*+----------------------+----------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------+ |
||||
| Address Block | 240.0.0.0/4 | |
||||
| Name | Reserved | |
||||
| RFC | [RFC1112], Section 4 | |
||||
| Allocation Date | August 1989 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+----------------------+*/ |
||||
MustIPv4Addr("240.0.0.0/4"), |
||||
|
||||
/*+----------------------+----------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------+ |
||||
| Address Block | 255.255.255.255/32 | |
||||
| Name | Limited Broadcast | |
||||
| RFC | [RFC0919], Section 7 | |
||||
| Allocation Date | October 1984 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | True | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------------+*/ |
||||
MustIPv4Addr("255.255.255.255/32"), |
||||
|
||||
/*+----------------------+------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+------------------+ |
||||
| Address Block | ::1/128 | |
||||
| Name | Loopback Address | |
||||
| RFC | [RFC4291] | |
||||
| Allocation Date | February 2006 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+------------------+*/ |
||||
MustIPv6Addr("::1/128"), |
||||
|
||||
/*+----------------------+---------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------------+ |
||||
| Address Block | ::/128 | |
||||
| Name | Unspecified Address | |
||||
| RFC | [RFC4291] | |
||||
| Allocation Date | February 2006 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+---------------------+*/ |
||||
MustIPv6Addr("::/128"), |
||||
|
||||
/*+----------------------+---------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------------+ |
||||
| Address Block | 64:ff9b::/96 | |
||||
| Name | IPv4-IPv6 Translat. | |
||||
| RFC | [RFC6052] | |
||||
| Allocation Date | October 2010 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | True | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------------+*/ |
||||
MustIPv6Addr("64:ff9b::/96"), |
||||
|
||||
/*+----------------------+---------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------------+ |
||||
| Address Block | ::ffff:0:0/96 | |
||||
| Name | IPv4-mapped Address | |
||||
| RFC | [RFC4291] | |
||||
| Allocation Date | February 2006 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+---------------------+*/ |
||||
MustIPv6Addr("::ffff:0:0/96"), |
||||
|
||||
/*+----------------------+----------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------------------+ |
||||
| Address Block | 100::/64 | |
||||
| Name | Discard-Only Address Block | |
||||
| RFC | [RFC6666] | |
||||
| Allocation Date | June 2012 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------------------+*/ |
||||
MustIPv6Addr("100::/64"), |
||||
|
||||
/*+----------------------+---------------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------------------+ |
||||
| Address Block | 2001::/23 | |
||||
| Name | IETF Protocol Assignments | |
||||
| RFC | [RFC2928] | |
||||
| Allocation Date | September 2000 | |
||||
| Termination Date | N/A | |
||||
| Source | False[1] | |
||||
| Destination | False[1] | |
||||
| Forwardable | False[1] | |
||||
| Global | False[1] | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------------------+*/ |
||||
// [1] Unless allowed by a more specific allocation.
|
||||
MustIPv6Addr("2001::/16"), |
||||
|
||||
/*+----------------------+----------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------+ |
||||
| Address Block | 2001::/32 | |
||||
| Name | TEREDO | |
||||
| RFC | [RFC4380] | |
||||
| Allocation Date | January 2006 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------+*/ |
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001::/16"),
|
||||
|
||||
/*+----------------------+----------------+ |
||||
| Attribute | Value | |
||||
+----------------------+----------------+ |
||||
| Address Block | 2001:2::/48 | |
||||
| Name | Benchmarking | |
||||
| RFC | [RFC5180] | |
||||
| Allocation Date | April 2008 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+----------------+*/ |
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001:2::/48"),
|
||||
|
||||
/*+----------------------+---------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------+ |
||||
| Address Block | 2001:db8::/32 | |
||||
| Name | Documentation | |
||||
| RFC | [RFC3849] | |
||||
| Allocation Date | July 2004 | |
||||
| Termination Date | N/A | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------+*/ |
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001:db8::/32"),
|
||||
|
||||
/*+----------------------+--------------+ |
||||
| Attribute | Value | |
||||
+----------------------+--------------+ |
||||
| Address Block | 2001:10::/28 | |
||||
| Name | ORCHID | |
||||
| RFC | [RFC4843] | |
||||
| Allocation Date | March 2007 | |
||||
| Termination Date | March 2014 | |
||||
| Source | False | |
||||
| Destination | False | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+--------------+*/ |
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001:10::/28"),
|
||||
|
||||
/*+----------------------+---------------+ |
||||
| Attribute | Value | |
||||
+----------------------+---------------+ |
||||
| Address Block | 2002::/16 [2] | |
||||
| Name | 6to4 | |
||||
| RFC | [RFC3056] | |
||||
| Allocation Date | February 2001 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | N/A [2] | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+---------------+*/ |
||||
// [2] See [RFC3056] for details.
|
||||
MustIPv6Addr("2002::/16"), |
||||
|
||||
/*+----------------------+--------------+ |
||||
| Attribute | Value | |
||||
+----------------------+--------------+ |
||||
| Address Block | fc00::/7 | |
||||
| Name | Unique-Local | |
||||
| RFC | [RFC4193] | |
||||
| Allocation Date | October 2005 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | True | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | False | |
||||
+----------------------+--------------+*/ |
||||
MustIPv6Addr("fc00::/7"), |
||||
|
||||
/*+----------------------+-----------------------+ |
||||
| Attribute | Value | |
||||
+----------------------+-----------------------+ |
||||
| Address Block | fe80::/10 | |
||||
| Name | Linked-Scoped Unicast | |
||||
| RFC | [RFC4291] | |
||||
| Allocation Date | February 2006 | |
||||
| Termination Date | N/A | |
||||
| Source | True | |
||||
| Destination | True | |
||||
| Forwardable | False | |
||||
| Global | False | |
||||
| Reserved-by-Protocol | True | |
||||
+----------------------+-----------------------+*/ |
||||
MustIPv6Addr("fe80::/10"), |
||||
}, |
||||
7335: SockAddrs{ |
||||
// [RFC7335] IPv4 Service Continuity Prefix
|
||||
MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations
|
||||
}, |
||||
ForwardingBlacklist: SockAddrs{ // Pseudo-RFC
|
||||
// Blacklist of non-forwardable IP blocks taken from RFC6890
|
||||
//
|
||||
// TODO: the attributes for forwardable should be
|
||||
// searcahble and embedded in the main list of RFCs
|
||||
// above.
|
||||
MustIPv4Addr("0.0.0.0/8"), |
||||
MustIPv4Addr("127.0.0.0/8"), |
||||
MustIPv4Addr("169.254.0.0/16"), |
||||
MustIPv4Addr("192.0.0.0/24"), |
||||
MustIPv4Addr("192.0.2.0/24"), |
||||
MustIPv4Addr("198.51.100.0/24"), |
||||
MustIPv4Addr("203.0.113.0/24"), |
||||
MustIPv4Addr("240.0.0.0/4"), |
||||
MustIPv4Addr("255.255.255.255/32"), |
||||
MustIPv6Addr("::1/128"), |
||||
MustIPv6Addr("::/128"), |
||||
MustIPv6Addr("::ffff:0:0/96"), |
||||
|
||||
// There is no way of expressing a whitelist per RFC2928
|
||||
// atm without creating a negative mask, which I don't
|
||||
// want to do atm.
|
||||
//MustIPv6Addr("2001::/23"),
|
||||
|
||||
MustIPv6Addr("2001:db8::/32"), |
||||
MustIPv6Addr("2001:10::/28"), |
||||
MustIPv6Addr("fe80::/10"), |
||||
}, |
||||
} |
||||
} |
||||
|
||||
// VisitAllRFCs iterates over all known RFCs and calls the visitor
|
||||
func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) { |
||||
rfcNetMap := KnownRFCs() |
||||
|
||||
// Blacklist of faux-RFCs. Don't show the world that we're abusing the
|
||||
// RFC system in this library.
|
||||
rfcBlacklist := map[uint]struct{}{ |
||||
ForwardingBlacklist: struct{}{}, |
||||
} |
||||
|
||||
for rfcNum, sas := range rfcNetMap { |
||||
if _, found := rfcBlacklist[rfcNum]; !found { |
||||
fn(rfcNum, sas) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,178 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
type SockAddrType int |
||||
type AttrName string |
||||
|
||||
const ( |
||||
TypeUnknown SockAddrType = 0x0 |
||||
TypeUnix = 0x1 |
||||
TypeIPv4 = 0x2 |
||||
TypeIPv6 = 0x4 |
||||
|
||||
// TypeIP is the union of TypeIPv4 and TypeIPv6
|
||||
TypeIP = 0x6 |
||||
) |
||||
|
||||
type SockAddr interface { |
||||
// CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC
|
||||
// networks, -1 if the receiver is contained within the RFC network, or
|
||||
// 1 if the address is not contained within the RFC.
|
||||
CmpRFC(rfcNum uint, sa SockAddr) int |
||||
|
||||
// Contains returns true if the SockAddr arg is contained within the
|
||||
// receiver
|
||||
Contains(SockAddr) bool |
||||
|
||||
// Equal allows for the comparison of two SockAddrs
|
||||
Equal(SockAddr) bool |
||||
|
||||
DialPacketArgs() (string, string) |
||||
DialStreamArgs() (string, string) |
||||
ListenPacketArgs() (string, string) |
||||
ListenStreamArgs() (string, string) |
||||
|
||||
// String returns the string representation of SockAddr
|
||||
String() string |
||||
|
||||
// Type returns the SockAddrType
|
||||
Type() SockAddrType |
||||
} |
||||
|
||||
// sockAddrAttrMap is a map of the SockAddr type-specific attributes.
|
||||
var sockAddrAttrMap map[AttrName]func(SockAddr) string |
||||
var sockAddrAttrs []AttrName |
||||
|
||||
func init() { |
||||
sockAddrInit() |
||||
} |
||||
|
||||
// New creates a new SockAddr from the string. The order in which New()
|
||||
// attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix.
|
||||
//
|
||||
// NOTE: New() relies on the heuristic wherein if the path begins with either a
|
||||
// '.' or '/' character before creating a new UnixSock. For UNIX sockets that
|
||||
// are absolute paths or are nested within a sub-directory, this works as
|
||||
// expected, however if the UNIX socket is contained in the current working
|
||||
// directory, this will fail unless the path begins with "./"
|
||||
// (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer
|
||||
// this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul
|
||||
// of this heuristic and be assumed to be a valid UNIX socket path (which they
|
||||
// are, but it is probably not what you want and you won't realize it until you
|
||||
// stat(2) the file system to discover it doesn't exist).
|
||||
func NewSockAddr(s string) (SockAddr, error) { |
||||
ipv4Addr, err := NewIPv4Addr(s) |
||||
if err == nil { |
||||
return ipv4Addr, nil |
||||
} |
||||
|
||||
ipv6Addr, err := NewIPv6Addr(s) |
||||
if err == nil { |
||||
return ipv6Addr, nil |
||||
} |
||||
|
||||
// Check to make sure the string begins with either a '.' or '/', or
|
||||
// contains a '/'.
|
||||
if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) { |
||||
unixSock, err := NewUnixSock(s) |
||||
if err == nil { |
||||
return unixSock, nil |
||||
} |
||||
} |
||||
|
||||
return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s) |
||||
} |
||||
|
||||
// ToIPAddr returns an IPAddr type or nil if the type conversion fails.
|
||||
func ToIPAddr(sa SockAddr) *IPAddr { |
||||
ipa, ok := sa.(IPAddr) |
||||
if !ok { |
||||
return nil |
||||
} |
||||
return &ipa |
||||
} |
||||
|
||||
// ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails.
|
||||
func ToIPv4Addr(sa SockAddr) *IPv4Addr { |
||||
switch v := sa.(type) { |
||||
case IPv4Addr: |
||||
return &v |
||||
default: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
// ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails.
|
||||
func ToIPv6Addr(sa SockAddr) *IPv6Addr { |
||||
switch v := sa.(type) { |
||||
case IPv6Addr: |
||||
return &v |
||||
default: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
// ToUnixSock returns a UnixSock type or nil if the type conversion fails.
|
||||
func ToUnixSock(sa SockAddr) *UnixSock { |
||||
switch v := sa.(type) { |
||||
case UnixSock: |
||||
return &v |
||||
default: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
// SockAddrAttr returns a string representation of an attribute for the given
|
||||
// SockAddr.
|
||||
func SockAddrAttr(sa SockAddr, selector AttrName) string { |
||||
fn, found := sockAddrAttrMap[selector] |
||||
if !found { |
||||
return "" |
||||
} |
||||
|
||||
return fn(sa) |
||||
} |
||||
|
||||
// String() for SockAddrType returns a string representation of the
|
||||
// SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown").
|
||||
func (sat SockAddrType) String() string { |
||||
switch sat { |
||||
case TypeIPv4: |
||||
return "IPv4" |
||||
case TypeIPv6: |
||||
return "IPv6" |
||||
// There is no concrete "IP" type. Leaving here as a reminder.
|
||||
// case TypeIP:
|
||||
// return "IP"
|
||||
case TypeUnix: |
||||
return "UNIX" |
||||
default: |
||||
panic("unsupported type") |
||||
} |
||||
} |
||||
|
||||
// sockAddrInit is called once at init()
|
||||
func sockAddrInit() { |
||||
sockAddrAttrs = []AttrName{ |
||||
"type", // type should be first
|
||||
"string", |
||||
} |
||||
|
||||
sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{ |
||||
"string": func(sa SockAddr) string { |
||||
return sa.String() |
||||
}, |
||||
"type": func(sa SockAddr) string { |
||||
return sa.Type().String() |
||||
}, |
||||
} |
||||
} |
||||
|
||||
// UnixSockAttrs returns a list of attributes supported by the UnixSock type
|
||||
func SockAddrAttrs() []AttrName { |
||||
return sockAddrAttrs |
||||
} |
@ -0,0 +1,193 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"bytes" |
||||
"sort" |
||||
) |
||||
|
||||
// SockAddrs is a slice of SockAddrs
|
||||
type SockAddrs []SockAddr |
||||
|
||||
func (s SockAddrs) Len() int { return len(s) } |
||||
func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
||||
|
||||
// CmpAddrFunc is the function signature that must be met to be used in the
|
||||
// OrderedAddrBy multiAddrSorter
|
||||
type CmpAddrFunc func(p1, p2 *SockAddr) int |
||||
|
||||
// multiAddrSorter implements the Sort interface, sorting the SockAddrs within.
|
||||
type multiAddrSorter struct { |
||||
addrs SockAddrs |
||||
cmp []CmpAddrFunc |
||||
} |
||||
|
||||
// Sort sorts the argument slice according to the Cmp functions passed to
|
||||
// OrderedAddrBy.
|
||||
func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) { |
||||
ms.addrs = sockAddrs |
||||
sort.Sort(ms) |
||||
} |
||||
|
||||
// OrderedAddrBy sorts SockAddr by the list of sort function pointers.
|
||||
func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter { |
||||
return &multiAddrSorter{ |
||||
cmp: cmpFuncs, |
||||
} |
||||
} |
||||
|
||||
// Len is part of sort.Interface.
|
||||
func (ms *multiAddrSorter) Len() int { |
||||
return len(ms.addrs) |
||||
} |
||||
|
||||
// Less is part of sort.Interface. It is implemented by looping along the
|
||||
// Cmp() functions until it finds a comparison that is either less than,
|
||||
// equal to, or greater than.
|
||||
func (ms *multiAddrSorter) Less(i, j int) bool { |
||||
p, q := &ms.addrs[i], &ms.addrs[j] |
||||
// Try all but the last comparison.
|
||||
var k int |
||||
for k = 0; k < len(ms.cmp)-1; k++ { |
||||
cmp := ms.cmp[k] |
||||
x := cmp(p, q) |
||||
switch x { |
||||
case -1: |
||||
// p < q, so we have a decision.
|
||||
return true |
||||
case 1: |
||||
// p > q, so we have a decision.
|
||||
return false |
||||
} |
||||
// p == q; try the next comparison.
|
||||
} |
||||
// All comparisons to here said "equal", so just return whatever the
|
||||
// final comparison reports.
|
||||
switch ms.cmp[k](p, q) { |
||||
case -1: |
||||
return true |
||||
case 1: |
||||
return false |
||||
default: |
||||
// Still a tie! Now what?
|
||||
return false |
||||
} |
||||
} |
||||
|
||||
// Swap is part of sort.Interface.
|
||||
func (ms *multiAddrSorter) Swap(i, j int) { |
||||
ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i] |
||||
} |
||||
|
||||
const ( |
||||
// NOTE (sean@): These constants are here for code readability only and
|
||||
// are sprucing up the code for readability purposes. Some of the
|
||||
// Cmp*() variants have confusing logic (especially when dealing with
|
||||
// mixed-type comparisons) and this, I think, has made it easier to grok
|
||||
// the code faster.
|
||||
sortReceiverBeforeArg = -1 |
||||
sortDeferDecision = 0 |
||||
sortArgBeforeReceiver = 1 |
||||
) |
||||
|
||||
// AscAddress is a sorting function to sort SockAddrs by their respective
|
||||
// address type. Non-equal types are deferred in the sort.
|
||||
func AscAddress(p1Ptr, p2Ptr *SockAddr) int { |
||||
p1 := *p1Ptr |
||||
p2 := *p2Ptr |
||||
|
||||
switch v := p1.(type) { |
||||
case IPv4Addr: |
||||
return v.CmpAddress(p2) |
||||
case IPv6Addr: |
||||
return v.CmpAddress(p2) |
||||
case UnixSock: |
||||
return v.CmpAddress(p2) |
||||
default: |
||||
return sortDeferDecision |
||||
} |
||||
} |
||||
|
||||
// AscPort is a sorting function to sort SockAddrs by their respective address
|
||||
// type. Non-equal types are deferred in the sort.
|
||||
func AscPort(p1Ptr, p2Ptr *SockAddr) int { |
||||
p1 := *p1Ptr |
||||
p2 := *p2Ptr |
||||
|
||||
switch v := p1.(type) { |
||||
case IPv4Addr: |
||||
return v.CmpPort(p2) |
||||
case IPv6Addr: |
||||
return v.CmpPort(p2) |
||||
default: |
||||
return sortDeferDecision |
||||
} |
||||
} |
||||
|
||||
// AscPrivate is a sorting function to sort "more secure" private values before
|
||||
// "more public" values. Both IPv4 and IPv6 are compared against RFC6890
|
||||
// (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and
|
||||
// IPv6 includes RFC4193).
|
||||
func AscPrivate(p1Ptr, p2Ptr *SockAddr) int { |
||||
p1 := *p1Ptr |
||||
p2 := *p2Ptr |
||||
|
||||
switch v := p1.(type) { |
||||
case IPv4Addr, IPv6Addr: |
||||
return v.CmpRFC(6890, p2) |
||||
default: |
||||
return sortDeferDecision |
||||
} |
||||
} |
||||
|
||||
// AscNetworkSize is a sorting function to sort SockAddrs based on their network
|
||||
// size. Non-equal types are deferred in the sort.
|
||||
func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int { |
||||
p1 := *p1Ptr |
||||
p2 := *p2Ptr |
||||
p1Type := p1.Type() |
||||
p2Type := p2.Type() |
||||
|
||||
// Network size operations on non-IP types make no sense
|
||||
if p1Type != p2Type && p1Type != TypeIP { |
||||
return sortDeferDecision |
||||
} |
||||
|
||||
ipA := p1.(IPAddr) |
||||
ipB := p2.(IPAddr) |
||||
|
||||
return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask())) |
||||
} |
||||
|
||||
// AscType is a sorting function to sort "more secure" types before
|
||||
// "less-secure" types.
|
||||
func AscType(p1Ptr, p2Ptr *SockAddr) int { |
||||
p1 := *p1Ptr |
||||
p2 := *p2Ptr |
||||
p1Type := p1.Type() |
||||
p2Type := p2.Type() |
||||
switch { |
||||
case p1Type < p2Type: |
||||
return sortReceiverBeforeArg |
||||
case p1Type == p2Type: |
||||
return sortDeferDecision |
||||
case p1Type > p2Type: |
||||
return sortArgBeforeReceiver |
||||
default: |
||||
return sortDeferDecision |
||||
} |
||||
} |
||||
|
||||
// FilterByType returns two lists: a list of matched and unmatched SockAddrs
|
||||
func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) { |
||||
matched = make(SockAddrs, 0, len(sas)) |
||||
excluded = make(SockAddrs, 0, len(sas)) |
||||
|
||||
for _, sa := range sas { |
||||
if sa.Type()&type_ != 0 { |
||||
matched = append(matched, sa) |
||||
} else { |
||||
excluded = append(excluded, sa) |
||||
} |
||||
} |
||||
return matched, excluded |
||||
} |
@ -0,0 +1,125 @@
|
||||
package template |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"text/template" |
||||
|
||||
"github.com/hashicorp/errwrap" |
||||
sockaddr "github.com/hashicorp/go-sockaddr" |
||||
) |
||||
|
||||
var ( |
||||
// SourceFuncs is a map of all top-level functions that generate
|
||||
// sockaddr data types.
|
||||
SourceFuncs template.FuncMap |
||||
|
||||
// SortFuncs is a map of all functions used in sorting
|
||||
SortFuncs template.FuncMap |
||||
|
||||
// FilterFuncs is a map of all functions used in sorting
|
||||
FilterFuncs template.FuncMap |
||||
|
||||
// HelperFuncs is a map of all functions used in sorting
|
||||
HelperFuncs template.FuncMap |
||||
) |
||||
|
||||
func init() { |
||||
SourceFuncs = template.FuncMap{ |
||||
// GetAllInterfaces - Returns an exhaustive set of IfAddr
|
||||
// structs available on the host. `GetAllInterfaces` is the
|
||||
// initial input and accessible as the initial "dot" in the
|
||||
// pipeline.
|
||||
"GetAllInterfaces": sockaddr.GetAllInterfaces, |
||||
|
||||
// GetDefaultInterfaces - Returns one IfAddr for every IP that
|
||||
// is on the interface containing the default route for the
|
||||
// host.
|
||||
"GetDefaultInterfaces": sockaddr.GetDefaultInterfaces, |
||||
|
||||
// GetPrivateInterfaces - Returns one IfAddr for every IP that
|
||||
// matches RFC 6890, are attached to the interface with the
|
||||
// default route, and are forwardable IP addresses. NOTE: RFC
|
||||
// 6890 is a more exhaustive version of RFC1918 because it spans
|
||||
// IPv4 and IPv6, however it doespermit the inclusion of likely
|
||||
// undesired addresses such as multicast, therefore our
|
||||
// definition of a "private" address also excludes
|
||||
// non-forwardable IP addresses (as defined by the IETF).
|
||||
"GetPrivateInterfaces": sockaddr.GetPrivateInterfaces, |
||||
|
||||
// GetPublicInterfaces - Returns a list of IfAddr that do not
|
||||
// match RFC 6890, are attached to the default route, and are
|
||||
// forwardable.
|
||||
"GetPublicInterfaces": sockaddr.GetPublicInterfaces, |
||||
} |
||||
|
||||
SortFuncs = template.FuncMap{ |
||||
"sort": sockaddr.SortIfBy, |
||||
} |
||||
|
||||
FilterFuncs = template.FuncMap{ |
||||
"exclude": sockaddr.ExcludeIfs, |
||||
"include": sockaddr.IncludeIfs, |
||||
} |
||||
|
||||
HelperFuncs = template.FuncMap{ |
||||
// Misc functions that operate on IfAddrs inputs
|
||||
"attr": sockaddr.IfAttr, |
||||
"join": sockaddr.JoinIfAddrs, |
||||
"limit": sockaddr.LimitIfAddrs, |
||||
"offset": sockaddr.OffsetIfAddrs, |
||||
"unique": sockaddr.UniqueIfAddrsBy, |
||||
|
||||
// Return a Private RFC 6890 IP address string that is attached
|
||||
// to the default route and a forwardable address.
|
||||
"GetPrivateIP": sockaddr.GetPrivateIP, |
||||
|
||||
// Return a Public RFC 6890 IP address string that is attached
|
||||
// to the default route and a forwardable address.
|
||||
"GetPublicIP": sockaddr.GetPublicIP, |
||||
|
||||
// Return the first IP address of the named interface, sorted by
|
||||
// the largest network size.
|
||||
"GetInterfaceIP": sockaddr.GetInterfaceIP, |
||||
} |
||||
} |
||||
|
||||
// Parse parses input as template input using the addresses available on the
|
||||
// host, then returns the string output if there are no errors.
|
||||
func Parse(input string) (string, error) { |
||||
addrs, err := sockaddr.GetAllInterfaces() |
||||
if err != nil { |
||||
return "", errwrap.Wrapf("unable to query interface addresses: {{err}}", err) |
||||
} |
||||
|
||||
return ParseIfAddrs(input, addrs) |
||||
} |
||||
|
||||
// ParseIfAddrs parses input as template input using the IfAddrs inputs, then
|
||||
// returns the string output if there are no errors.
|
||||
func ParseIfAddrs(input string, ifAddrs sockaddr.IfAddrs) (string, error) { |
||||
return ParseIfAddrsTemplate(input, ifAddrs, template.New("sockaddr.Parse")) |
||||
} |
||||
|
||||
// ParseIfAddrsTemplate parses input as template input using the IfAddrs inputs,
|
||||
// then returns the string output if there are no errors.
|
||||
func ParseIfAddrsTemplate(input string, ifAddrs sockaddr.IfAddrs, tmplIn *template.Template) (string, error) { |
||||
// Create a template, add the function map, and parse the text.
|
||||
tmpl, err := tmplIn.Option("missingkey=error"). |
||||
Funcs(SourceFuncs). |
||||
Funcs(SortFuncs). |
||||
Funcs(FilterFuncs). |
||||
Funcs(HelperFuncs). |
||||
Parse(input) |
||||
if err != nil { |
||||
return "", errwrap.Wrapf(fmt.Sprintf("unable to parse template %+q: {{err}}", input), err) |
||||
} |
||||
|
||||
var outWriter bytes.Buffer |
||||
err = tmpl.Execute(&outWriter, ifAddrs) |
||||
if err != nil { |
||||
return "", errwrap.Wrapf(fmt.Sprintf("unable to execute sockaddr input %+q: {{err}}", input), err) |
||||
} |
||||
|
||||
return outWriter.String(), nil |
||||
} |
@ -0,0 +1,135 @@
|
||||
package sockaddr |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
type UnixSock struct { |
||||
SockAddr |
||||
path string |
||||
} |
||||
type UnixSocks []*UnixSock |
||||
|
||||
// unixAttrMap is a map of the UnixSockAddr type-specific attributes.
|
||||
var unixAttrMap map[AttrName]func(UnixSock) string |
||||
var unixAttrs []AttrName |
||||
|
||||
func init() { |
||||
unixAttrInit() |
||||
} |
||||
|
||||
// NewUnixSock creates an UnixSock from a string path. String can be in the
|
||||
// form of either URI-based string (e.g. `file:///etc/passwd`), an absolute
|
||||
// path (e.g. `/etc/passwd`), or a relative path (e.g. `./foo`).
|
||||
func NewUnixSock(s string) (ret UnixSock, err error) { |
||||
ret.path = s |
||||
return ret, nil |
||||
} |
||||
|
||||
// CmpAddress follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its name lexically sorts before arg
|
||||
// - 0 if the SockAddr arg is not a UnixSock, or is a UnixSock with the same path.
|
||||
// - 1 If the argument should sort first.
|
||||
func (us UnixSock) CmpAddress(sa SockAddr) int { |
||||
usb, ok := sa.(UnixSock) |
||||
if !ok { |
||||
return sortDeferDecision |
||||
} |
||||
|
||||
return strings.Compare(us.Path(), usb.Path()) |
||||
} |
||||
|
||||
// DialPacketArgs returns the arguments required to be passed to net.DialUnix()
|
||||
// with the `unixgram` network type.
|
||||
func (us UnixSock) DialPacketArgs() (network, dialArgs string) { |
||||
return "unixgram", us.path |
||||
} |
||||
|
||||
// DialStreamArgs returns the arguments required to be passed to net.DialUnix()
|
||||
// with the `unix` network type.
|
||||
func (us UnixSock) DialStreamArgs() (network, dialArgs string) { |
||||
return "unix", us.path |
||||
} |
||||
|
||||
// Equal returns true if a SockAddr is equal to the receiving UnixSock.
|
||||
func (us UnixSock) Equal(sa SockAddr) bool { |
||||
usb, ok := sa.(UnixSock) |
||||
if !ok { |
||||
return false |
||||
} |
||||
|
||||
if us.Path() != usb.Path() { |
||||
return false |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
// ListenPacketArgs returns the arguments required to be passed to
|
||||
// net.ListenUnixgram() with the `unixgram` network type.
|
||||
func (us UnixSock) ListenPacketArgs() (network, dialArgs string) { |
||||
return "unixgram", us.path |
||||
} |
||||
|
||||
// ListenStreamArgs returns the arguments required to be passed to
|
||||
// net.ListenUnix() with the `unix` network type.
|
||||
func (us UnixSock) ListenStreamArgs() (network, dialArgs string) { |
||||
return "unix", us.path |
||||
} |
||||
|
||||
// MustUnixSock is a helper method that must return an UnixSock or panic on
|
||||
// invalid input.
|
||||
func MustUnixSock(addr string) UnixSock { |
||||
us, err := NewUnixSock(addr) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("Unable to create a UnixSock from %+q: %v", addr, err)) |
||||
} |
||||
return us |
||||
} |
||||
|
||||
// Path returns the given path of the UnixSock
|
||||
func (us UnixSock) Path() string { |
||||
return us.path |
||||
} |
||||
|
||||
// String returns the path of the UnixSock
|
||||
func (us UnixSock) String() string { |
||||
return fmt.Sprintf("%+q", us.path) |
||||
} |
||||
|
||||
// Type is used as a type switch and returns TypeUnix
|
||||
func (UnixSock) Type() SockAddrType { |
||||
return TypeUnix |
||||
} |
||||
|
||||
// UnixSockAttrs returns a list of attributes supported by the UnixSockAddr type
|
||||
func UnixSockAttrs() []AttrName { |
||||
return unixAttrs |
||||
} |
||||
|
||||
// UnixSockAttr returns a string representation of an attribute for the given
|
||||
// UnixSock.
|
||||
func UnixSockAttr(us UnixSock, attrName AttrName) string { |
||||
fn, found := unixAttrMap[attrName] |
||||
if !found { |
||||
return "" |
||||
} |
||||
|
||||
return fn(us) |
||||
} |
||||
|
||||
// unixAttrInit is called once at init()
|
||||
func unixAttrInit() { |
||||
// Sorted for human readability
|
||||
unixAttrs = []AttrName{ |
||||
"path", |
||||
} |
||||
|
||||
unixAttrMap = map[AttrName]func(us UnixSock) string{ |
||||
"path": func(us UnixSock) string { |
||||
return us.Path() |
||||
}, |
||||
} |
||||
} |
Loading…
Reference in new issue