From 70a20b4d261036c01dad38134097ba34afa60461 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 19 Dec 2016 18:10:26 +0000 Subject: [PATCH] Generate peer name / mac address in Go --- net/mac.go | 38 +++++++++++++++++++++++++++++++++ net/uuid.go | 42 +++++++++++++++++++++++++++++++++++++ prog/weaveutil/main.go | 1 + prog/weaveutil/unique_id.go | 20 ++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 net/mac.go create mode 100644 net/uuid.go create mode 100644 prog/weaveutil/unique_id.go diff --git a/net/mac.go b/net/mac.go new file mode 100644 index 00000000..05864970 --- /dev/null +++ b/net/mac.go @@ -0,0 +1,38 @@ +package net + +import ( + "crypto/rand" + "crypto/sha256" + "net" +) + +func RandomMAC() (net.HardwareAddr, error) { + mac := make([]byte, 6) + if _, err := rand.Read(mac); err != nil { + return nil, err + } + + setUnicastAndLocal(mac) + + return net.HardwareAddr(mac), nil +} + +func MACfromUUID(uuid []byte) net.HardwareAddr { + hash := sha256.New() + // We salt the input just as a precaution to avoid clashes with + // other applications who might have had the bright idea of + // generating MACs in the same way. + hash.Write([]byte("9oBJ0Jmip-")) + hash.Write(uuid) + sum := hash.Sum(nil) + + setUnicastAndLocal(sum) + + return net.HardwareAddr(sum[:6]) +} + +// In the first byte of the MAC, the 'multicast' bit should be +// clear and 'locally administered' bit should be set. +func setUnicastAndLocal(mac []byte) { + mac[0] = (mac[0] & 0xFE) | 0x02 +} diff --git a/net/uuid.go b/net/uuid.go new file mode 100644 index 00000000..f3cd2ebc --- /dev/null +++ b/net/uuid.go @@ -0,0 +1,42 @@ +package net + +import ( + "fmt" + "io/ioutil" + "net" + "os" +) + +func getSystemUUID(hostRoot string) ([]byte, error) { + machineid, err := ioutil.ReadFile(hostRoot + "/etc/machine-id") + if os.IsNotExist(err) { + machineid, _ = ioutil.ReadFile(hostRoot + "/var/lib/dbus/machine-id") + } + uuid, err := ioutil.ReadFile(hostRoot + "/sys/class/dmi/id/product_uuid") + if os.IsNotExist(err) { + uuid, _ = ioutil.ReadFile(hostRoot + "/sys/hypervisor/uuid") + } + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if len(machineid)+len(uuid) == 0 { + return nil, fmt.Errorf("Empty system uuid") + } + return append(machineid, uuid...), nil +} + +// GetSystemPeerName returns an ID derived from concatenated machine-id +// (either systemd or dbus), the system (aka bios) UUID and the +// hypervisor UUID. It is tweaked and formatted to be usable as a mac address +func GetSystemPeerName(hostRoot string) (string, error) { + var mac net.HardwareAddr + if uuid, err := getSystemUUID(hostRoot); err == nil { + mac = MACfromUUID(uuid) + } else { + mac, err = RandomMAC() + if err != nil { + return "", err + } + } + return mac.String(), nil +} diff --git a/prog/weaveutil/main.go b/prog/weaveutil/main.go index 8322a013..10e771f3 100644 --- a/prog/weaveutil/main.go +++ b/prog/weaveutil/main.go @@ -36,6 +36,7 @@ func init() { "cni-ipam": cniIPAM, "expose-nat": exposeNAT, "bridge-ip": bridgeIP, + "unique-id": uniqueID, } } diff --git a/prog/weaveutil/unique_id.go b/prog/weaveutil/unique_id.go new file mode 100644 index 00000000..456c69eb --- /dev/null +++ b/prog/weaveutil/unique_id.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + + weavenet "github.com/weaveworks/weave/net" +) + +func uniqueID(args []string) error { + if len(args) != 1 { + cmdUsage("unique-id", "") + } + hostRoot := args[0] + uid, err := weavenet.GetSystemPeerName(hostRoot) + if err != nil { + return err + } + fmt.Printf(uid) + return nil +}