Skip to content

Commit 7809824

Browse files
c-robinsonChad Robinson
authored and
Chad Robinson
committed
IID submodule + small fixes
new IID module for creating IPv6 Interface Identifiers - create Modified EUI-64 addresses - create "semantically opaque" addresses - check IIDs for conflicts with IANA reserved IIDs - make iana/README and iid/README look similar - small change to improve iplib test coverage
1 parent 98bf95d commit 7809824

File tree

7 files changed

+721
-13
lines changed

7 files changed

+721
-13
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ An enhancement of `net.IPNet` providing features such as:
4747
- [iana](https://github.com/c-robinson/iplib/tree/master/iana) - a module for referencing
4848
IP netblocks against the [Internet Assigned Numbers Authority's](https://www.iana.org/)
4949
Special IP Address Registry
50+
- [iid](https://github.com/c-robinson/iplib/tree/master/iid) - a module for
51+
generating and validating IPv6 Interface Identifiers, including [RFC4291](https://tools.ietf.org/html/rfc4291)
52+
modified EUI64 and [RFC7217](https://tools.ietf.org/html/rfc7217)
53+
Semantically Opaque addresses
5054

5155
## Installing
5256

TODO.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ include:
5252

5353
- functions for allocating /64s as if they were IPs as per [RFC7934 section 6](https://tools.ietf.org/html/rfc7934#section-6)
5454

55-
- functions for generating interface identifiers for link-local and global
56-
use based on Modified IEEE EUI-64 hardware addresses as described in
57-
[RFC 4291](https://tools.ietf.org/html/rfc4291#section-2.5.1)
58-
59-
- The list of RFCs starting with RFC 4941 (and containing at least 7217
60-
and 8064) describe mechanisms for enhancing the privacy of self-generated
61-
addresses by pseudo-randomly modifying the last 64 bits of an address.
62-
This might make for an interesting sub-module
63-
6455
#### RFC1918
6556
The most important address-space on the (IPv4) internet is the RFC1918 private
6657
address block designation that is effectively on the inside of every home and

iana/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ and exposes it as a data structure. Functions allow a caller to compare the
1111
registry against `net.IP` and `iplib.Net` objects to see if they contain or
1212
are contained within an reserved IP address block.
1313

14+
## Installing
15+
16+
```sh
17+
go get -u github.com/c-robinson/iplib/iana
18+
```
19+
20+
## Using IANA
21+
22+
Here are examples comparing against both an address and a network. Note that in
23+
the network case it is entirely possible for a broad-enough network to contain
24+
multiple reservations. If this is the case all reservations will be returned.
25+
1426
```go
1527
package main
1628

@@ -22,7 +34,6 @@ import (
2234
"github.com/c-robinson/iplib/iana"
2335
)
2436

25-
2637
func main() {
2738
ipa := net.ParseIP("144.21.21.21")
2839
ipb := net.ParseIP("192.168.12.5")

iid/README.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# iid
2+
[![Documentation](https://godoc.org/github.com/c-robinson/iplib?status.svg)](http://godoc.org/github.com/c-robinson/iplib/iid)
3+
[![CircleCI](https://circleci.com/gh/c-robinson/iplib/tree/master.svg?style=svg)](https://circleci.com/gh/c-robinson/iplib/tree/master)
4+
[![Go Report Card](https://goreportcard.com/badge/github.com/c-robinson/iplib)](https://goreportcard.com/report/github.com/c-robinson/iplib)
5+
[![Coverage Status](https://coveralls.io/repos/github/c-robinson/iplib/badge.svg?branch=master)](https://coveralls.io/github/c-robinson/iplib?branch=master)
6+
7+
This package implements functions for generating and validating IPv6 Interface
8+
Identifiers (IID's) for use in link-local, global unicast and Stateless Address
9+
Autoconfiguration (SLAAC). For the purposes of this module an IID is an IPv6
10+
address constructed, somehow, from information which uniquely identifies a
11+
given interface on a network, and is unique _within_ that network.
12+
13+
## Installing
14+
15+
```sh
16+
go get -u github.com/c-robinson/iplib/iid
17+
```
18+
19+
## Using IID
20+
21+
This library contains functions for uniting `net.IP` and `net.HardwareAddr`
22+
addresses in order to generate globally unique IPv6 addresses. The simplest of
23+
which is the "Modified EUI-64 address" described in [RFC4291 section 2.5.1](https://tools.ietf.org/html/rfc4291#section-2.5.1)
24+
25+
```go
26+
package main
27+
28+
import (
29+
"fmt"
30+
"net"
31+
32+
"github.com/c-robinson/iplib/iid"
33+
)
34+
35+
func main() {
36+
ip := net.ParseIP("2001:db8:1111:2222::")
37+
hw, _ := net.ParseMAC("99:88:77:66:55:44")
38+
myiid := iid.MakeEUI64Addr(ip, hw, iid.ScopeGlobal)
39+
fmt.Println(myiid) // will be "2001:db8:1111:2222:9b88:77ff:fe66:5544"
40+
}
41+
```
42+
43+
EUI64 is fine for a local subnet, but since it is tied to a hardware address
44+
and guessable by design it is a privacy nightmare as outlined in [RFC4941](https://tools.ietf.org/html/rfc4941).
45+
46+
[RFC7217](https://tools.ietf.org/html/rfc7217) defines an algorithm to create
47+
"semantically opaque" IID's based on the local interface by hashing the address
48+
with a secret key, a counter, and some optional additional data. The resulting
49+
IID is pseudo-random (the same inputs will result in the same outputs) so care
50+
must be taken while generating it. This function has some requirements:
51+
52+
- `secret` a `[]byte` that is a closely-held secret key
53+
- `counter` an `int64`, this is what provides the address its mutability. The
54+
RFC specifies that this counter should be incremented every time the same
55+
ipaddr/hwaddr pair is used as input and should be stored in non-volatile
56+
memory to preserve it
57+
- `netid` is an optional parameter to improve the privacy of the results, it
58+
is suggested that this be some other bit of information from the local
59+
network such as an 802.11 SSID.
60+
61+
NOTE: it is possible, though very unlikely, that an address generated this way
62+
might collide with the [IANA Reserved Interface Identifier List](https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml),
63+
if this happens an `iid.ErrIIDAddressCollision` will be returned. If so
64+
`counter` should be incremented and the function re-run.
65+
66+
```go
67+
package main
68+
69+
import (
70+
"fmt"
71+
"net"
72+
73+
"github.com/c-robinson/iplib/iid"
74+
)
75+
76+
func main() {
77+
ip := net.ParseIP("2001:db8::")
78+
hw, _ := net.ParseMAC("77:88:99:aa:bb:cc")
79+
counter := int64(1)
80+
netid := []byte("01234567")
81+
secret := []byte("secret")
82+
83+
myiid, err := iid.MakeOpaqueAddr(ip, hw, counter, netid, secret)
84+
if err != nil {
85+
fmt.Println("a very unlikely collision occurred!")
86+
}
87+
fmt.Println(myiid) // will be "2001:db8::c6fa:ba02:41ab:282c"
88+
}
89+
```
90+
91+
`MakeOpaqueIID()` is an implementation of the RFC's specified function
92+
using its' preferred [SHA256](https://golang.org/pkg/crypto/sha256/)
93+
hashing algorithm and a `iid.ScopeGlobal` scope. If either of these is not to
94+
your liking you can roll your own by calling the underlying function.
95+
96+
NOTE: if you use any hashing algorithm other than SHA224 or SHA256 you will
97+
need to import both `"crypto"` _and_ the crypto submodule with your specific
98+
implementation first (e.g. `_ "golang.org/x/crypto/blake2s"`. Also note that
99+
the RFC _specifically prohibits_ MD5 as being too insecure for use. Here's an
100+
example using [SHA512](https://golang.org/pkg/crypto/sha512/)
101+
102+
```go
103+
package main
104+
105+
import (
106+
"crypto"
107+
_ "crypto/sha512"
108+
"fmt"
109+
"net"
110+
111+
"github.com/c-robinson/iplib/iid"
112+
)
113+
114+
func main() {
115+
ip := net.ParseIP("2001:db8::")
116+
hw, _ := net.ParseMAC("77:88:99:aa:bb:cc")
117+
counter := int64(1)
118+
netid := []byte("01234567")
119+
secret := []byte("secret")
120+
121+
myiid, err := iid.GenerateRFC7217Addr(ip, hw, counter, netid, secret, crypto.SHA384, iid.ScopeGlobal)
122+
if err != nil {
123+
fmt.Println("a very unlikely collision occurred!")
124+
}
125+
fmt.Println(myiid) // will be "2001:db8::51b3:c6b0:4e14:3519"
126+
}
127+
```
128+
129+
Finally, to be entirely RFC7217-compliant a function _should_ check it's
130+
results to make sure they don't collide with the IANA Reserved Interface
131+
Identifier List. In the name of "using every part of the buffalo" the function
132+
is exposed for the extremely unlikely case where anyone needs it:
133+
134+
```go
135+
package main
136+
137+
import (
138+
"fmt"
139+
"net"
140+
141+
"github.com/c-robinson/iplib/iid"
142+
)
143+
144+
func main() {
145+
ip := net.ParseIP("2001:db8::0200:5EFF:FE00:5211")
146+
res := iid.GetReservationsForIP(ip)
147+
fmt.Println(res.RFC) // will be "RFC4291"
148+
fmt.Println(res.Title) // "Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block"
149+
}
150+
```

0 commit comments

Comments
 (0)