Merge pull request #2563 from hashicorp/f-sockaddr-0.7

F sockaddr 0.7
This commit is contained in:
Sean Chittenden 2016-12-02 22:38:32 +11:00 committed by GitHub
commit f0ab957711
22 changed files with 4772 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package agent
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -12,6 +13,7 @@ import (
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"time"
@ -21,6 +23,7 @@ import (
"github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/logger"
"github.com/hashicorp/consul/types"
"github.com/hashicorp/go-sockaddr/template"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/serf/coordinate"
"github.com/hashicorp/serf/serf"
@ -140,6 +143,12 @@ func Create(config *Config, logOutput io.Writer, logWriter *logger.LogWriter,
// Try to get an advertise address
if config.AdvertiseAddr != "" {
ipStr, err := parseSingleIPTemplate(config.AdvertiseAddr)
if err != nil {
return nil, fmt.Errorf("Advertise address resolution failed: %v", err)
}
config.AdvertiseAddr = ipStr
if ip := net.ParseIP(config.AdvertiseAddr); ip == nil {
return nil, fmt.Errorf("Failed to parse advertise address: %v", config.AdvertiseAddr)
}
@ -161,6 +170,12 @@ func Create(config *Config, logOutput io.Writer, logWriter *logger.LogWriter,
// Try to get an advertise address for the wan
if config.AdvertiseAddrWan != "" {
ipStr, err := parseSingleIPTemplate(config.AdvertiseAddrWan)
if err != nil {
return nil, fmt.Errorf("Advertise WAN address resolution failed: %v", err)
}
config.AdvertiseAddrWan = ipStr
if ip := net.ParseIP(config.AdvertiseAddrWan); ip == nil {
return nil, fmt.Errorf("Failed to parse advertise address for wan: %v", config.AdvertiseAddrWan)
}
@ -192,6 +207,10 @@ func Create(config *Config, logOutput io.Writer, logWriter *logger.LogWriter,
endpoints: make(map[string]string),
}
if err := agent.resolveTmplAddrs(); err != nil {
return nil, err
}
// Initialize the local state.
agent.state.Init(config, agent.logger)
@ -400,6 +419,121 @@ func (a *Agent) consulConfig() *consul.Config {
return base
}
// parseSingleIPTemplate is used as a helper function to parse out a single IP
// address from a config parameter.
func parseSingleIPTemplate(ipTmpl string) (string, error) {
out, err := template.Parse(ipTmpl)
if err != nil {
return "", fmt.Errorf("Unable to parse address template %q: %v", ipTmpl, err)
}
ips := strings.Split(out, " ")
switch len(ips) {
case 0:
return "", errors.New("No addresses found, please configure one.")
case 1:
return ips[0], nil
default:
return "", fmt.Errorf("Multiple addresses found (%q), please configure one.", out)
}
}
// resolveTmplAddrs iterates over the myriad of addresses in the agent's config
// and performs go-sockaddr/template Parse on each known address in case the
// user specified a template config for any of their values.
func (a *Agent) resolveTmplAddrs() error {
if a.config.AdvertiseAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.AdvertiseAddr)
if err != nil {
return fmt.Errorf("Advertise address resolution failed: %v", err)
}
a.config.AdvertiseAddr = ipStr
}
if a.config.Addresses.DNS != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.DNS)
if err != nil {
return fmt.Errorf("DNS address resolution failed: %v", err)
}
a.config.Addresses.DNS = ipStr
}
if a.config.Addresses.HTTP != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.HTTP)
if err != nil {
return fmt.Errorf("HTTP address resolution failed: %v", err)
}
a.config.Addresses.HTTP = ipStr
}
if a.config.Addresses.HTTPS != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.HTTPS)
if err != nil {
return fmt.Errorf("HTTPS address resolution failed: %v", err)
}
a.config.Addresses.HTTPS = ipStr
}
if a.config.Addresses.RPC != "" {
ipStr, err := parseSingleIPTemplate(a.config.Addresses.RPC)
if err != nil {
return fmt.Errorf("RPC address resolution failed: %v", err)
}
a.config.Addresses.RPC = ipStr
}
if a.config.AdvertiseAddrWan != "" {
ipStr, err := parseSingleIPTemplate(a.config.AdvertiseAddrWan)
if err != nil {
return fmt.Errorf("Advertise WAN address resolution failed: %v", err)
}
a.config.AdvertiseAddrWan = ipStr
}
if a.config.BindAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.BindAddr)
if err != nil {
return fmt.Errorf("Bind address resolution failed: %v", err)
}
a.config.BindAddr = ipStr
}
if a.config.ClientAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.ClientAddr)
if err != nil {
return fmt.Errorf("Client address resolution failed: %v", err)
}
a.config.ClientAddr = ipStr
}
if a.config.SerfLanBindAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.SerfLanBindAddr)
if err != nil {
return fmt.Errorf("Serf LAN Address resolution failed: %v", err)
}
a.config.SerfLanBindAddr = ipStr
}
if a.config.SerfWanBindAddr != "" {
ipStr, err := parseSingleIPTemplate(a.config.SerfWanBindAddr)
if err != nil {
return fmt.Errorf("Serf WAN Address resolution failed: %v", err)
}
a.config.SerfWanBindAddr = ipStr
}
// Parse all tagged addresses
for k, v := range a.config.TaggedAddresses {
ipStr, err := parseSingleIPTemplate(v)
if err != nil {
return fmt.Errorf("%s address resolution failed: %v", k, err)
}
a.config.TaggedAddresses[k] = ipStr
}
return nil
}
// setupServer is used to initialize the Consul server
func (a *Agent) setupServer() error {
config := a.consulConfig()

View File

@ -967,6 +967,12 @@ func DecodeConfig(r io.Reader) (*Config, error) {
}
if result.AdvertiseAddrs.SerfLanRaw != "" {
ipStr, err := parseSingleIPTemplate(result.AdvertiseAddrs.SerfLanRaw)
if err != nil {
return nil, fmt.Errorf("Serf Advertise LAN address resolution failed: %v", err)
}
result.AdvertiseAddrs.SerfLanRaw = ipStr
addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.SerfLanRaw)
if err != nil {
return nil, fmt.Errorf("AdvertiseAddrs.SerfLan is invalid: %v", err)
@ -975,6 +981,12 @@ func DecodeConfig(r io.Reader) (*Config, error) {
}
if result.AdvertiseAddrs.SerfWanRaw != "" {
ipStr, err := parseSingleIPTemplate(result.AdvertiseAddrs.SerfWanRaw)
if err != nil {
return nil, fmt.Errorf("Serf Advertise WAN address resolution failed: %v", err)
}
result.AdvertiseAddrs.SerfWanRaw = ipStr
addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.SerfWanRaw)
if err != nil {
return nil, fmt.Errorf("AdvertiseAddrs.SerfWan is invalid: %v", err)
@ -983,6 +995,12 @@ func DecodeConfig(r io.Reader) (*Config, error) {
}
if result.AdvertiseAddrs.RPCRaw != "" {
ipStr, err := parseSingleIPTemplate(result.AdvertiseAddrs.RPCRaw)
if err != nil {
return nil, fmt.Errorf("RPC Advertise address resolution failed: %v", err)
}
result.AdvertiseAddrs.RPCRaw = ipStr
addr, err := net.ResolveTCPAddr("tcp", result.AdvertiseAddrs.RPCRaw)
if err != nil {
return nil, fmt.Errorf("AdvertiseAddrs.RPC is invalid: %v", err)

373
vendor/github.com/hashicorp/go-sockaddr/LICENSE generated vendored Normal file
View File

@ -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.

52
vendor/github.com/hashicorp/go-sockaddr/Makefile generated vendored Normal file
View File

@ -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

126
vendor/github.com/hashicorp/go-sockaddr/ifaddr.go generated vendored Normal file
View File

@ -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
},
}
}

935
vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go generated vendored Normal file
View File

@ -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")
}

30
vendor/github.com/hashicorp/go-sockaddr/ifaddrs_bsd.go generated vendored Normal file
View File

@ -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
}

View File

@ -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)")
}

View File

@ -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
}

View File

@ -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
}

View File

@ -0,0 +1,38 @@
package sockaddr
import "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) {
var cmd []string = defaultWindowsIfNameCmd()
ifNameOut, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
cmd = defaultWindowsIPConfigCmd()
ipconfigOut, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
if err != nil {
return "", err
}
return ifName, nil
}

65
vendor/github.com/hashicorp/go-sockaddr/ifattr.go generated vendored Normal file
View File

@ -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)
}

151
vendor/github.com/hashicorp/go-sockaddr/ipaddr.go generated vendored Normal file
View File

@ -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())
},
}
}

98
vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go generated vendored Normal file
View File

@ -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()
}

505
vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go generated vendored Normal file
View File

@ -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))
},
}
}

591
vendor/github.com/hashicorp/go-sockaddr/ipv6addr.go generated vendored Normal file
View File

@ -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
}

947
vendor/github.com/hashicorp/go-sockaddr/rfc.go generated vendored Normal file
View File

@ -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)
}
}
}

178
vendor/github.com/hashicorp/go-sockaddr/sockaddr.go generated vendored Normal file
View File

@ -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
}

193
vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go generated vendored Normal file
View File

@ -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
}

View File

@ -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
}

135
vendor/github.com/hashicorp/go-sockaddr/unixsock.go generated vendored Normal file
View File

@ -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()
},
}
}

12
vendor/vendor.json vendored
View File

@ -419,6 +419,18 @@
"revision": "6e85be8fee1dcaa02c0eaaac2df5a8fbecf94145",
"revisionTime": "2016-09-30T03:51:02Z"
},
{
"checksumSHA1": "LmCRW89WaBzau5RaVIhx8QHwLYo=",
"path": "github.com/hashicorp/go-sockaddr",
"revision": "33afa667d8f9a6ca9d435a8f8c6e87af423c9356",
"revisionTime": "2016-12-02T07:02:37Z"
},
{
"checksumSHA1": "Y+c+ahUug8/vK+cWRLatV5aB4ps=",
"path": "github.com/hashicorp/go-sockaddr/template",
"revision": "a99c57b5a5f48c51607e63089075fe7434fe219a",
"revisionTime": "2016-12-02T03:16:41Z"
},
{
"checksumSHA1": "xZ7Ban1x//6uUIU1xtrTbCYNHBc=",
"path": "github.com/hashicorp/go-syslog",