From a8db4e3c50790c83f8ba459517cc70481a014d83 Mon Sep 17 00:00:00 2001 From: Andrea Barberio Date: Wed, 6 Dec 2017 19:53:13 +0000 Subject: DHCPv6 is now an interface; DHCPv6Message and DHCPv6RelayMessage are implementations --- dhcpv6/client.go | 18 ++++++------- dhcpv6/dhcpv6.go | 75 ++++++++++++++++++++++++++++++--------------------- dhcpv6/dhcpv6_test.go | 22 +++++++-------- 3 files changed, 64 insertions(+), 51 deletions(-) diff --git a/dhcpv6/client.go b/dhcpv6/client.go index 787439d..6bb1a91 100644 --- a/dhcpv6/client.go +++ b/dhcpv6/client.go @@ -25,29 +25,29 @@ type Client struct { } // Make a stateful DHCPv6 request -func (c *Client) Exchange(ifname string, d *DHCPv6) ([]DHCPv6, error) { - conversation := make([]DHCPv6, 1) +func (c *Client) Exchange(ifname string, solicit DHCPv6) ([]DHCPv6, error) { + conversation := make([]DHCPv6, 0) var err error // Solicit - if d == nil { - d, err = NewSolicitForInterface(ifname) + if solicit == nil { + solicit, err = NewSolicitForInterface(ifname) if err != nil { return conversation, err } } - conversation[0] = *d - advertise, err := c.ExchangeSolicitAdvertise(ifname, d) + conversation = append(conversation, solicit) + advertise, err := c.ExchangeSolicitAdvertise(ifname, solicit) if err != nil { return conversation, err } - conversation = append(conversation, *advertise) + conversation = append(conversation, advertise) // TODO request/reply return conversation, nil } -func (c *Client) ExchangeSolicitAdvertise(ifname string, d *DHCPv6) (*DHCPv6, error) { +func (c *Client) ExchangeSolicitAdvertise(ifname string, solicit DHCPv6) (DHCPv6, error) { // if no LocalAddr is specified, get the interface's link-local address var laddr net.UDPAddr if c.LocalAddr == nil { @@ -93,7 +93,7 @@ func (c *Client) ExchangeSolicitAdvertise(ifname string, d *DHCPv6) (*DHCPv6, er conn.SetWriteDeadline(time.Now().Add(wtimeout)) // send the SOLICIT packet out - _, err = conn.WriteTo(d.ToBytes(), &raddr) + _, err = conn.WriteTo(solicit.ToBytes(), &raddr) if err != nil { return nil, err } diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go index 6b664d2..0505301 100644 --- a/dhcpv6/dhcpv6.go +++ b/dhcpv6/dhcpv6.go @@ -13,12 +13,25 @@ import ( const HeaderSize = 4 -type DHCPv6 struct { - message MessageType +type DHCPv6 interface { + Type() MessageType + ToBytes() []byte + Summary() string +} + +type DHCPv6Message struct { + messageType MessageType transactionID uint32 // only 24 bits are used though options []options.Option } +type DHCPv6RelayMessage struct { + messageType MessageType + hopCount uint8 + linkAddr net.IP + peerAddr net.IP +} + func BytesToTransactionID(data []byte) (*uint32, error) { // return a uint32 from a sequence of bytes, representing a transaction ID. // Transaction IDs are three-bytes long. If the provided data is shorter than @@ -57,7 +70,7 @@ func GenerateTransactionID() (*uint32, error) { return tid, nil } -func FromBytes(data []byte) (*DHCPv6, error) { +func FromBytes(data []byte) (DHCPv6, error) { if len(data) < HeaderSize { return nil, fmt.Errorf("Invalid DHCPv6 header: shorter than %v bytes", HeaderSize) } @@ -65,8 +78,8 @@ func FromBytes(data []byte) (*DHCPv6, error) { if err != nil { return nil, err } - d := DHCPv6{ - message: MessageType(data[0]), + d := DHCPv6Message{ + messageType: MessageType(data[0]), transactionID: *tid, } options, err := options.FromBytes(data[4:]) @@ -77,13 +90,13 @@ func FromBytes(data []byte) (*DHCPv6, error) { return &d, nil } -func New() (*DHCPv6, error) { +func NewMessage() (*DHCPv6Message, error) { tid, err := GenerateTransactionID() if err != nil { return nil, err } - d := DHCPv6{ - message: SOLICIT, + d := DHCPv6Message{ + messageType: SOLICIT, transactionID: *tid, } return &d, nil @@ -98,8 +111,8 @@ func GetTime() uint32 { // Create a new SOLICIT message with DUID-LLT, using the given network // interface's hardware address and current time -func NewSolicitForInterface(ifname string) (*DHCPv6, error) { - d, err := New() +func NewSolicitForInterface(ifname string) (*DHCPv6Message, error) { + d, err := NewMessage() if err != nil { return nil, err } @@ -133,29 +146,29 @@ func NewSolicitForInterface(ifname string) (*DHCPv6, error) { return d, nil } -func (d *DHCPv6) Message() MessageType { - return d.message +func (d *DHCPv6Message) Type() MessageType { + return d.messageType } -func (d *DHCPv6) SetMessage(message MessageType) { - if MessageToString[message] == "" { - log.Printf("Warning: unknown DHCPv6 message: %v", message) +func (d *DHCPv6Message) SetMessage(messageType MessageType) { + if MessageToString[messageType] == "" { + log.Printf("Warning: unknown DHCPv6 message type: %v", messageType) } - d.message = message + d.messageType = messageType } -func (d *DHCPv6) MessageToString() string { - if m := MessageToString[d.message]; m != "" { +func (d *DHCPv6Message) MessageToString() string { + if m := MessageToString[d.messageType]; m != "" { return m } return "Invalid" } -func (d *DHCPv6) TransactionID() uint32 { +func (d *DHCPv6Message) TransactionID() uint32 { return d.transactionID } -func (d *DHCPv6) SetTransactionID(tid uint32) { +func (d *DHCPv6Message) SetTransactionID(tid uint32) { ttid := tid & 0x00ffffff if ttid != tid { log.Printf("Warning: truncating transaction ID that is longer than 24 bits: %v", tid) @@ -163,28 +176,28 @@ func (d *DHCPv6) SetTransactionID(tid uint32) { d.transactionID = ttid } -func (d *DHCPv6) Options() []options.Option { +func (d *DHCPv6Message) Options() []options.Option { return d.options } -func (d *DHCPv6) SetOptions(options []options.Option) { +func (d *DHCPv6Message) SetOptions(options []options.Option) { d.options = options } -func (d *DHCPv6) AddOption(option options.Option) { +func (d *DHCPv6Message) AddOption(option options.Option) { d.options = append(d.options, option) } -func (d *DHCPv6) String() string { - return fmt.Sprintf("DHCPv6(message=%v transactionID=0x%06x, %d options)", +func (d *DHCPv6Message) String() string { + return fmt.Sprintf("DHCPv6Message(messageType=%v transactionID=0x%06x, %d options)", d.MessageToString(), d.TransactionID(), len(d.options), ) } -func (d *DHCPv6) Summary() string { +func (d *DHCPv6Message) Summary() string { ret := fmt.Sprintf( - "DHCPv6\n"+ - " message=%v\n"+ + "DHCPv6Message\n"+ + " messageType=%v\n"+ " transactionid=0x%06x\n", d.MessageToString(), d.TransactionID(), @@ -200,11 +213,11 @@ func (d *DHCPv6) Summary() string { return ret } -// Convert a DHCPv6 structure into its binary representation, suitable for being +// Convert a DHCPv6Message structure into its binary representation, suitable for being // sent over the network -func (d *DHCPv6) ToBytes() []byte { +func (d *DHCPv6Message) ToBytes() []byte { var ret []byte - ret = append(ret, byte(d.message)) + ret = append(ret, byte(d.messageType)) tidBytes := make([]byte, 4) binary.BigEndian.PutUint32(tidBytes, d.transactionID) ret = append(ret, tidBytes[1:4]...) // discard the first byte diff --git a/dhcpv6/dhcpv6_test.go b/dhcpv6/dhcpv6_test.go index 084a8b4..3d0c5fc 100644 --- a/dhcpv6/dhcpv6_test.go +++ b/dhcpv6/dhcpv6_test.go @@ -45,16 +45,16 @@ func TestGenerateTransactionID(t *testing.T) { } } -func TestNew(t *testing.T) { - d, err := New() +func TestNewMessage(t *testing.T) { + d, err := NewMessage() if err != nil { t.Fatal(err) } if d == nil { t.Fatal("Expected non-nil DHCPv6, got nil instead") } - if d.message != SOLICIT { - t.Fatalf("Invalid message type. Expected %v, got %v", SOLICIT, d.message) + if d.messageType != SOLICIT { + t.Fatalf("Invalid message type. Expected %v, got %v", SOLICIT, d.messageType) } if d.transactionID == 0 { t.Fatal("Invalid Transaction ID, expected non-zero, got zero") @@ -65,17 +65,17 @@ func TestNew(t *testing.T) { } func TestSettersAndGetters(t *testing.T) { - d := DHCPv6{} + d := DHCPv6Message{} // Message d.SetMessage(SOLICIT) - msg := d.Message() + msg := d.Type() if msg != SOLICIT { - t.Fatalf("Invalid Message. Expected %v, got %v", SOLICIT, msg) + t.Fatalf("Invalid message type. Expected %v, got %v", SOLICIT, msg) } d.SetMessage(ADVERTISE) - msg = d.Message() + msg = d.Type() if msg != ADVERTISE { - t.Fatalf("Invalid Message. Expected %v, got %v", ADVERTISE, msg) + t.Fatalf("Invalid message type. Expected %v, got %v", ADVERTISE, msg) } // TransactionID d.SetTransactionID(12345) @@ -100,7 +100,7 @@ func TestSettersAndGetters(t *testing.T) { } func TestAddOption(t *testing.T) { - d := DHCPv6{} + d := DHCPv6Message{} opts := d.Options() if len(opts) != 0 { t.Fatalf("Invalid Options. Expected empty array, got %v", opts) @@ -117,7 +117,7 @@ func TestAddOption(t *testing.T) { } func TestToBytes(t *testing.T) { - d := DHCPv6{} + d := DHCPv6Message{} d.SetMessage(SOLICIT) d.SetTransactionID(0xabcdef) opt := options.OptionGeneric{OptionCode: 0, OptionData: []byte{}} -- cgit v1.2.3