Skip to content

Commit

Permalink
Extract mac address from non DUID-LL[T] requests using relayinfo's EU…
Browse files Browse the repository at this point in the history
…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 7f3b385
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ $ go get github.com/golang/glog
$ go get github.com/krolaw/dhcp4 $ go get github.com/krolaw/dhcp4
$ go get github.com/facebookgo/ensure $ go get github.com/facebookgo/ensure
$ go get github.com/hashicorp/golang-lru $ go get github.com/hashicorp/golang-lru
$ go get golang.org/x/time/rate
$ go get github.com/mdlayher/eui64
``` ```


# Installation # Installation
Expand Down
5 changes: 5 additions & 0 deletions glog_logger.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ func (l glogLogger) Log(msg dhcplb.LogMessage) error {
sample["link-addr"] = link.String() sample["link-addr"] = link.String()
peer, _ := packet.PeerAddr() peer, _ := packet.PeerAddr()
sample["peer-addr"] = peer.String() sample["peer-addr"] = peer.String()

duid_type_name, err := packet.DuidTypeName()
if err == nil {
sample["duid_type"] = duid_type_name
}
} }
} }


Expand Down
44 changes: 40 additions & 4 deletions lib/packet6.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"github.com/mdlayher/eui64"
"net" "net"
) )


Expand Down Expand Up @@ -75,6 +76,7 @@ const (
DuidLLT DuidType = iota + 1 DuidLLT DuidType = iota + 1
DuidEN DuidEN
DuidLL DuidLL
DuidUUID
) )


func (p Packet6) getOption(option OptionType) ([]byte, error) { func (p Packet6) getOption(option OptionType) ([]byte, error) {
Expand Down Expand Up @@ -177,18 +179,52 @@ func (p Packet6) Duid() ([]byte, error) {
return m.getOption(ClientID) return m.getOption(ClientID)
} }


// Mac returns the Mac addressed embededded in the DUID, note that thiw only func (p Packet6) DuidTypeName() (string, error) {
// works with type DuidLL and DuidLLT. An error will be returned otherwise. 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) { func (p Packet6) Mac() ([]byte, error) {
duid, err := p.Duid() duid, err := p.Duid()
if err != nil { if err != nil {
return nil, err return nil, err
} }
duidType := DuidType(binary.BigEndian.Uint16(duid[0:2])) duidType := DuidType(binary.BigEndian.Uint16(duid[0:2]))
if duidType != DuidLLT && duidType != DuidLL { 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 return duid[len(duid)-6:], nil
} }


Expand Down
40 changes: 40 additions & 0 deletions lib/packet6_test.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ var relayForwBytes = []byte{
// interface id option // interface id option
0x00, 0x12, 0x00, 0x04, 0x09, 0x01, 0x08, 0xca} 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 //ADVERTISE response to SOLICIT wrapped in Relay-Repl
var relayReplBytes = []byte{ var relayReplBytes = []byte{
0x0d, // message type = relay-repl 0x0d, // message type = relay-repl
Expand Down Expand Up @@ -143,6 +164,25 @@ func TestDuid(t *testing.T) {
ensure.DeepEqual(t, duid, expected) 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 // basic sanity check that packet decodes the correct way after being
// encapsulated in a relay-forward // encapsulated in a relay-forward
func TestEncapsulateSanity(t *testing.T) { func TestEncapsulateSanity(t *testing.T) {
Expand Down

0 comments on commit 7f3b385

Please sign in to comment.