Permalink
Browse files

Extract mac address from non DUID-LL[T] requests using relayinfo's EU…

…I-64 address in peer-address field, if present

Summary:
DUID-EN or DUID-UUID are client ids that don't contain mac address information in them, dhcplb can still extract the mac address by looking at the RelayInfo header in RelayFwd messages, the peer-address field there contains an EUI-64 address.

It is possible to extract the mac address from there.

See https://supportforums.cisco.com/document/100566/understanding-ipv6-eui-64-bit-address

We do that using https://github.com/mdlayher/eui64

Reviewed By: fiorix

Differential Revision: D5562502

fbshipit-source-id: f33bcdd734cd0bad06843945c8e829f71e901d8e
  • Loading branch information...
pallotron authored and facebook-github-bot committed Aug 4, 2017
1 parent e285051 commit 7f3b3859478a4f19a15984d97c96fceaa89e982b
Showing with 87 additions and 4 deletions.
  1. +2 −0 README.md
  2. +5 −0 glog_logger.go
  3. +40 −4 lib/packet6.go
  4. +40 −0 lib/packet6_test.go
View
@@ -97,6 +97,8 @@ $ go get github.com/golang/glog
$ go get github.com/krolaw/dhcp4
$ go get github.com/facebookgo/ensure
$ go get github.com/hashicorp/golang-lru
$ go get golang.org/x/time/rate
$ go get github.com/mdlayher/eui64
```
# Installation
View
@@ -69,6 +69,11 @@ func (l glogLogger) Log(msg dhcplb.LogMessage) error {
sample["link-addr"] = link.String()
peer, _ := packet.PeerAddr()
sample["peer-addr"] = peer.String()
duid_type_name, err := packet.DuidTypeName()
if err == nil {
sample["duid_type"] = duid_type_name
}
}
}
View
@@ -13,6 +13,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/mdlayher/eui64"
"net"
)
@@ -75,6 +76,7 @@ const (
DuidLLT DuidType = iota + 1
DuidEN
DuidLL
DuidUUID
)
func (p Packet6) getOption(option OptionType) ([]byte, error) {
@@ -177,18 +179,52 @@ func (p Packet6) Duid() ([]byte, error) {
return m.getOption(ClientID)
}
// Mac returns the Mac addressed embededded in the DUID, note that thiw only
// works with type DuidLL and DuidLLT. An error will be returned otherwise.
func (p Packet6) DuidTypeName() (string, error) {
duid, err := p.Duid()
if err != nil {
return "", err
}
duidType := DuidType(binary.BigEndian.Uint16(duid[0:2]))
switch duidType {
case DuidLLT:
return "DUID-LLT", nil
case DuidLL:
return "DUID-LL", nil
case DuidEN:
return "DUID-EN", nil
case DuidUUID:
return "DUID-UUID", nil
default:
return "Unknown", nil
}
}
// Mac returns the Mac addressed embededded in the DUID, note that this only
// works with type DuidLL and DuidLLT. If the request is not using DUID-LL[T]
// then we look into the PeerAddr field in the RelayInfo header.
// This contains the EUI-64 address of the client making the request, populated
// by the dhcp relay, it is possible to extract the mac address from that IP.
// If a mac address cannot be fonud an error will be returned.
func (p Packet6) Mac() ([]byte, error) {
duid, err := p.Duid()
if err != nil {
return nil, err
}
duidType := DuidType(binary.BigEndian.Uint16(duid[0:2]))
if duidType != DuidLLT && duidType != DuidLL {
return nil, fmt.Errorf("Cannot extract MAC from DUID type %d", duidType)
// look at PeerAddress if there
ip, err := p.PeerAddr()
if err != nil {
return nil, err
} else {
_, mac, err := eui64.ParseIP(ip)
if err != nil {
return nil, err
}
return mac, nil
}
}
// last 6 bytes of the duid will be the MAC address
// for DUIDLL[T], the last 6 bytes of the duid will be the MAC address
return duid[len(duid)-6:], nil
}
View
@@ -40,6 +40,27 @@ var relayForwBytes = []byte{
// interface id option
0x00, 0x12, 0x00, 0x04, 0x09, 0x01, 0x08, 0xca}
//SOLICIT message wrapped in Relay-Forw
var relayForwBytesDuidUUID = []byte{
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x26, 0x8a, 0x07, 0xff, 0xfe, 0x56,
0xdc, 0xa4, 0x00, 0x12, 0x00, 0x06, 0x24, 0x8a,
0x07, 0x56, 0xdc, 0xa4, 0x00, 0x09, 0x00, 0x5a,
0x06, 0x7d, 0x9b, 0xca, 0x00, 0x01, 0x00, 0x12,
0x00, 0x04, 0xb7, 0xfd, 0x0a, 0x8c, 0x1b, 0x14,
0x10, 0xaa, 0xeb, 0x0a, 0x5b, 0x3f, 0xe8, 0x9d,
0x0f, 0x56, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x17,
0x00, 0x18, 0x00, 0x17, 0x00, 0x18, 0x00, 0x01,
0x00, 0x08, 0x00, 0x02, 0xff, 0xff, 0x00, 0x03,
0x00, 0x28, 0x07, 0x56, 0xdc, 0xa4, 0x00, 0x00,
0x0e, 0x10, 0x00, 0x00, 0x15, 0x18, 0x00, 0x05,
0x00, 0x18, 0x26, 0x20, 0x01, 0x0d, 0xc0, 0x82,
0x90, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xaf, 0xa0, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00,
0x1d, 0x4c}
//ADVERTISE response to SOLICIT wrapped in Relay-Repl
var relayReplBytes = []byte{
0x0d, // message type = relay-repl
@@ -143,6 +164,25 @@ func TestDuid(t *testing.T) {
ensure.DeepEqual(t, duid, expected)
}
func TestDuidUUID(t *testing.T) {
packet := Packet6(relayForwBytesDuidUUID)
duid, err := packet.Duid()
if err != nil {
t.Fatalf("Error extracting duid: %s", err)
}
expected := []byte{0x00, 0x04, 0xb7, 0xfd, 0x0a, 0x8c, 0x1b, 0x14,
0x10, 0xaa, 0xeb, 0x0a, 0x5b, 0x3f, 0xe8, 0x9d,
0x0f, 0x56}
ensure.DeepEqual(t, duid, expected)
mac, err_mac := packet.Mac()
if err_mac != nil {
t.Fatalf("Error extracting mac from peer-address relayinfo: %s", err_mac)
}
if FormatID(mac) != "24:8a:07:56:dc:a4" {
t.Fatalf("Expected mac %s but got %s", "24:8a:07:56:de:b0", FormatID(mac))
}
}
// basic sanity check that packet decodes the correct way after being
// encapsulated in a relay-forward
func TestEncapsulateSanity(t *testing.T) {

0 comments on commit 7f3b385

Please sign in to comment.