119 lines
5.5 KiB
Markdown
119 lines
5.5 KiB
Markdown
|
# go-sockaddr
|
||
|
|
||
|
## `sockaddr` Library
|
||
|
|
||
|
Socket address convenience functions for Go. `go-sockaddr` is a convenience
|
||
|
library that makes doing the right thing with IP addresses easy. `go-sockaddr`
|
||
|
is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family
|
||
|
of `sockaddr_t` types (see below for an ascii diagram). Library documentation
|
||
|
is available
|
||
|
at
|
||
|
[https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr).
|
||
|
The primary intent of the library was to make it possible to define heuristics
|
||
|
for selecting the correct IP addresses when a configuration is evaluated at
|
||
|
runtime. See
|
||
|
the
|
||
|
[docs](https://godoc.org/github.com/hashicorp/go-sockaddr),
|
||
|
[`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template),
|
||
|
tests,
|
||
|
and
|
||
|
[CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
|
||
|
for details and hints as to how to use this library.
|
||
|
|
||
|
For example, with this library it is possible to find an IP address that:
|
||
|
|
||
|
* is attached to a default route
|
||
|
([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces))
|
||
|
* is contained within a CIDR block (['IfByNetwork()'](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork))
|
||
|
* is an RFC1918 address
|
||
|
([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
|
||
|
* is ordered
|
||
|
([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where
|
||
|
`args` includes, but is not limited
|
||
|
to,
|
||
|
[`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType),
|
||
|
[`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize))
|
||
|
* excludes all IPv6 addresses
|
||
|
([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType))
|
||
|
* is larger than a `/32`
|
||
|
([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize))
|
||
|
* is not on a `down` interface
|
||
|
([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs))
|
||
|
* preferences an IPv6 address over an IPv4 address
|
||
|
([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) +
|
||
|
[`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and
|
||
|
* excludes any IP in RFC6890 address
|
||
|
([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
|
||
|
|
||
|
Or any combination or variation therein.
|
||
|
|
||
|
There are also a few simple helper functions such as `GetPublicIP` and
|
||
|
`GetPrivateIP` which both return strings and select the first public or private
|
||
|
IP address on the default interface, respectively. Similarly, there is also a
|
||
|
helper function called `GetInterfaceIP` which returns the first usable IP
|
||
|
address on the named interface.
|
||
|
|
||
|
## `sockaddr` CLI
|
||
|
|
||
|
Given the possible complexity of the `sockaddr` library, there is a CLI utility
|
||
|
that accompanies the library, also
|
||
|
called
|
||
|
[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr).
|
||
|
The
|
||
|
[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
|
||
|
utility exposes nearly all of the functionality of the library and can be used
|
||
|
either as an administrative tool or testing tool. To install
|
||
|
the
|
||
|
[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr),
|
||
|
run:
|
||
|
|
||
|
```text
|
||
|
$ go get -u github.com/hashicorp/go-sockaddr/cmd/sockaddr
|
||
|
```
|
||
|
|
||
|
If you're familiar with UNIX's `sockaddr` struct's, the following diagram
|
||
|
mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and
|
||
|
interfaces will be helpful:
|
||
|
|
||
|
```
|
||
|
+-------------------------------------------------------+
|
||
|
| |
|
||
|
| sockaddr |
|
||
|
| SockAddr |
|
||
|
| |
|
||
|
| +--------------+ +----------------------------------+ |
|
||
|
| | sockaddr_un | | | |
|
||
|
| | SockAddrUnix | | sockaddr_in{,6} | |
|
||
|
| +--------------+ | IPAddr | |
|
||
|
| | | |
|
||
|
| | +-------------+ +--------------+ | |
|
||
|
| | | sockaddr_in | | sockaddr_in6 | | |
|
||
|
| | | IPv4Addr | | IPv6Addr | | |
|
||
|
| | +-------------+ +--------------+ | |
|
||
|
| | | |
|
||
|
| +----------------------------------+ |
|
||
|
| |
|
||
|
+-------------------------------------------------------+
|
||
|
```
|
||
|
|
||
|
## Inspiration and Design
|
||
|
|
||
|
There were many subtle inspirations that led to this design, but the most direct
|
||
|
inspiration for the filtering syntax was
|
||
|
OpenBSD's
|
||
|
[`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall
|
||
|
syntax that lets you select the first IP address on a given named interface.
|
||
|
The original problem stemmed from:
|
||
|
|
||
|
* needing to create immutable images using [Packer](https://www.packer.io) that
|
||
|
ran the [Consul](https://www.consul.io) process (Consul can only use one IP
|
||
|
address at a time);
|
||
|
* images that may or may not have multiple interfaces or IP addresses at
|
||
|
runtime; and
|
||
|
* we didn't want to rely on configuration management to render out the correct
|
||
|
IP address if the VM image was being used in an auto-scaling group.
|
||
|
|
||
|
Instead we needed some way to codify a heuristic that would correctly select the
|
||
|
right IP address but the input parameters were not known when the image was
|
||
|
created.
|