diff --git a/client.go b/client.go index 1d4a348..ea64c16 100644 --- a/client.go +++ b/client.go @@ -2,7 +2,6 @@ package dhcp4client import ( "bytes" - "crypto/rand" "net" "time" @@ -19,11 +18,10 @@ type Client struct { timeout time.Duration //Time before we timeout. broadcast bool //Set the Bcast flag in BOOTP Flags connection connection //The Connection Method to use + generateXID func([]byte) //Function Used to Generate a XID } -/* - * Abstracts the type of underlying socket used - */ +//Abstracts the type of underlying socket used type connection interface { Close() error Write(packet []byte) error @@ -33,8 +31,9 @@ type connection interface { func New(options ...func(*Client) error) (*Client, error) { c := Client{ - timeout: time.Second * 10, - broadcast: true, + timeout: time.Second * 10, + broadcast: true, + generateXID: CryptoGenerateXID, } err := c.SetOption(options...) @@ -98,9 +97,14 @@ func Connection(conn connection) func(*Client) error { } } -/* - * Close Connections - */ +func GenerateXID(g func([]byte)) func(*Client) error { + return func(c *Client) error { + c.generateXID = g + return nil + } +} + +//Close Connections func (c *Client) Close() error { if c.connection != nil { return c.connection.Close() @@ -108,9 +112,7 @@ func (c *Client) Close() error { return nil } -/* - * Send the Discovery Packet to the Broadcast Channel - */ +//Send the Discovery Packet to the Broadcast Channel func (c *Client) SendDiscoverPacket() (dhcp4.Packet, error) { discoveryPacket := c.DiscoverPacket() discoveryPacket.PadToMinSize() @@ -118,10 +120,8 @@ func (c *Client) SendDiscoverPacket() (dhcp4.Packet, error) { return discoveryPacket, c.SendPacket(discoveryPacket) } -/* - * Retreive Offer... - * Wait for the offer for a specific Discovery Packet. - */ +//Retreive Offer... +//Wait for the offer for a specific Discovery Packet. func (c *Client) GetOffer(discoverPacket *dhcp4.Packet) (dhcp4.Packet, error) { for { c.connection.SetReadTimeout(c.timeout) @@ -153,9 +153,7 @@ func (c *Client) GetOffer(discoverPacket *dhcp4.Packet) (dhcp4.Packet, error) { } -/* - * Send Request Based On the offer Received. - */ +//Send Request Based On the offer Received. func (c *Client) SendRequest(offerPacket *dhcp4.Packet) (dhcp4.Packet, error) { requestPacket := c.RequestPacket(offerPacket) requestPacket.PadToMinSize() @@ -163,10 +161,8 @@ func (c *Client) SendRequest(offerPacket *dhcp4.Packet) (dhcp4.Packet, error) { return requestPacket, c.SendPacket(requestPacket) } -/* - * Retreive Acknowledgement - * Wait for the offer for a specific Request Packet. - */ +//Retreive Acknowledgement +//Wait for the offer for a specific Request Packet. func (c *Client) GetAcknowledgement(requestPacket *dhcp4.Packet) (dhcp4.Packet, error) { for { c.connection.SetReadTimeout(c.timeout) @@ -197,9 +193,7 @@ func (c *Client) GetAcknowledgement(requestPacket *dhcp4.Packet) (dhcp4.Packet, } } -/* - * Send Decline to the received acknowledgement. - */ +//Send Decline to the received acknowledgement. func (c *Client) SendDecline(acknowledgementPacket *dhcp4.Packet) (dhcp4.Packet, error) { declinePacket := c.DeclinePacket(acknowledgementPacket) declinePacket.PadToMinSize() @@ -207,21 +201,15 @@ func (c *Client) SendDecline(acknowledgementPacket *dhcp4.Packet) (dhcp4.Packet, return declinePacket, c.SendPacket(declinePacket) } -/* - * Send a DHCP Packet. - */ +//Send a DHCP Packet. func (c *Client) SendPacket(packet dhcp4.Packet) error { return c.connection.Write(packet) } -/* - * Create Discover Packet - */ +//Create Discover Packet func (c *Client) DiscoverPacket() dhcp4.Packet { messageid := make([]byte, 4) - if _, err := rand.Read(messageid); err != nil { - panic(err) - } + c.generateXID(messageid) packet := dhcp4.NewPacket(dhcp4.BootRequest) packet.SetCHAddr(c.hardwareAddr) @@ -233,9 +221,7 @@ func (c *Client) DiscoverPacket() dhcp4.Packet { return packet } -/* - * Create Request Packet - */ +//Create Request Packet func (c *Client) RequestPacket(offerPacket *dhcp4.Packet) dhcp4.Packet { offerOptions := offerPacket.ParseOptions() @@ -251,18 +237,13 @@ func (c *Client) RequestPacket(offerPacket *dhcp4.Packet) dhcp4.Packet { packet.AddOption(dhcp4.OptionRequestedIPAddress, (offerPacket.YIAddr()).To4()) packet.AddOption(dhcp4.OptionServerIdentifier, offerOptions[dhcp4.OptionServerIdentifier]) - //packet.PadToMinSize() return packet } -/* - * Create Request Packet For a Renew - */ +//Create Request Packet For a Renew func (c *Client) RenewalRequestPacket(acknowledgement *dhcp4.Packet) dhcp4.Packet { messageid := make([]byte, 4) - if _, err := rand.Read(messageid); err != nil { - panic(err) - } + c.generateXID(messageid) acknowledgementOptions := acknowledgement.ParseOptions() @@ -278,18 +259,13 @@ func (c *Client) RenewalRequestPacket(acknowledgement *dhcp4.Packet) dhcp4.Packe packet.AddOption(dhcp4.OptionRequestedIPAddress, (acknowledgement.YIAddr()).To4()) packet.AddOption(dhcp4.OptionServerIdentifier, acknowledgementOptions[dhcp4.OptionServerIdentifier]) - //packet.PadToMinSize() return packet } -/* - * Create Release Packet For a Release - */ +//Create Release Packet For a Release func (c *Client) ReleasePacket(acknowledgement *dhcp4.Packet) dhcp4.Packet { messageid := make([]byte, 4) - if _, err := rand.Read(messageid); err != nil { - panic(err) - } + c.generateXID(messageid) acknowledgementOptions := acknowledgement.ParseOptions() @@ -302,18 +278,13 @@ func (c *Client) ReleasePacket(acknowledgement *dhcp4.Packet) dhcp4.Packet { packet.AddOption(dhcp4.OptionDHCPMessageType, []byte{byte(dhcp4.Release)}) packet.AddOption(dhcp4.OptionServerIdentifier, acknowledgementOptions[dhcp4.OptionServerIdentifier]) - //packet.PadToMinSize() return packet } -/* - * Create Decline Packet - */ +//Create Decline Packet func (c *Client) DeclinePacket(acknowledgement *dhcp4.Packet) dhcp4.Packet { messageid := make([]byte, 4) - if _, err := rand.Read(messageid); err != nil { - panic(err) - } + c.generateXID(messageid) acknowledgementOptions := acknowledgement.ParseOptions() @@ -325,13 +296,11 @@ func (c *Client) DeclinePacket(acknowledgement *dhcp4.Packet) dhcp4.Packet { packet.AddOption(dhcp4.OptionRequestedIPAddress, (acknowledgement.YIAddr()).To4()) packet.AddOption(dhcp4.OptionServerIdentifier, acknowledgementOptions[dhcp4.OptionServerIdentifier]) - //packet.PadToMinSize() return packet } -/* - * Lets do a Full DHCP Request. - */ + +//Lets do a Full DHCP Request. func (c *Client) Request() (bool, dhcp4.Packet, error) { discoveryPacket, err := c.SendDiscoverPacket() if err != nil { @@ -361,10 +330,8 @@ func (c *Client) Request() (bool, dhcp4.Packet, error) { return true, acknowledgement, nil } -/* - * Renew a lease backed on the Acknowledgement Packet. - * Returns Sucessfull, The AcknoledgementPacket, Any Errors - */ +//Renew a lease backed on the Acknowledgement Packet. +//Returns Sucessfull, The AcknoledgementPacket, Any Errors func (c *Client) Renew(acknowledgement dhcp4.Packet) (bool, dhcp4.Packet, error) { renewRequest := c.RenewalRequestPacket(&acknowledgement) renewRequest.PadToMinSize() @@ -387,10 +354,8 @@ func (c *Client) Renew(acknowledgement dhcp4.Packet) (bool, dhcp4.Packet, error) return true, newAcknowledgement, nil } -/* - * Release a lease backed on the Acknowledgement Packet. - * Returns Any Errors - */ +//Release a lease backed on the Acknowledgement Packet. +//Returns Any Errors func (c *Client) Release(acknowledgement dhcp4.Packet) error { release := c.ReleasePacket(&acknowledgement) release.PadToMinSize() diff --git a/client_test.go b/client_test.go index bc25326..b696501 100644 --- a/client_test.go +++ b/client_test.go @@ -1,14 +1,14 @@ -package dhcp4client +package dhcp4client_test import ( "log" "net" "testing" + + "github.com/d2g/dhcp4client" ) -/* - * Example Client - */ +//Example Client func Test_ExampleClient(test *testing.T) { var err error @@ -19,15 +19,17 @@ func Test_ExampleClient(test *testing.T) { //Create a connection to use //We need to set the connection ports to 1068 and 1067 so we don't need root access - c, err := NewInetSock(SetLocalAddr(net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 1068}), SetRemoteAddr(net.UDPAddr{IP: net.IPv4bcast, Port: 1067})) + c, err := dhcp4client.NewInetSock(dhcp4client.SetLocalAddr(net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 1068}), dhcp4client.SetRemoteAddr(net.UDPAddr{IP: net.IPv4bcast, Port: 1067})) if err != nil { test.Error("Client Connection Generation:" + err.Error()) } + defer c.Close() - exampleClient, err := New(HardwareAddr(m), Connection(c)) + exampleClient, err := dhcp4client.New(dhcp4client.HardwareAddr(m), dhcp4client.Connection(c)) if err != nil { test.Fatalf("Error:%v\n", err) } + defer exampleClient.Close() success, acknowledgementpacket, err := exampleClient.Request() @@ -67,3 +69,48 @@ func Test_ExampleClient(test *testing.T) { } } + +//Example Client (With MathGID) +func Test_ExampleClientWithMathGenerateXID(test *testing.T) { + var err error + + m, err := net.ParseMAC("08-00-27-00-A8-E8") + if err != nil { + log.Printf("MAC Error:%v\n", err) + } + + //Create a connection to use + //We need to set the connection ports to 1068 and 1067 so we don't need root access + c, err := dhcp4client.NewInetSock(dhcp4client.SetLocalAddr(net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 1068}), dhcp4client.SetRemoteAddr(net.UDPAddr{IP: net.IPv4bcast, Port: 1067})) + if err != nil { + test.Error("Client Connection Generation:" + err.Error()) + } + defer c.Close() + + // If you ar using MathGenerateXID then you are responsible for seeding math/rand + exampleClient, err := dhcp4client.New(dhcp4client.HardwareAddr(m), dhcp4client.Connection(c), dhcp4client.GenerateXID(dhcp4client.MathGenerateXID)) + if err != nil { + test.Fatalf("Error:%v\n", err) + } + defer exampleClient.Close() + + success, acknowledgementpacket, err := exampleClient.Request() + + test.Logf("Success:%v\n", success) + test.Logf("Packet:%v\n", acknowledgementpacket) + + if err != nil { + networkError, ok := err.(*net.OpError) + if ok && networkError.Timeout() { + test.Log("Test Skipping as it didn't find a DHCP Server") + test.SkipNow() + } + test.Fatalf("Error:%v\n", err) + } + + if !success { + test.Error("We didn't sucessfully get a DHCP Lease?") + } else { + log.Printf("IP Received:%v\n", acknowledgementpacket.YIAddr().String()) + } +} diff --git a/generatexid.go b/generatexid.go new file mode 100644 index 0000000..6e9ffbc --- /dev/null +++ b/generatexid.go @@ -0,0 +1,18 @@ +package dhcp4client + +import ( + cryptorand "crypto/rand" + mathrand "math/rand" +) + +func CryptoGenerateXID(b []byte) { + if _, err := cryptorand.Read(b); err != nil { + panic(err) + } +} + +func MathGenerateXID(b []byte) { + if _, err := mathrand.Read(b); err != nil { + panic(err) + } +} diff --git a/generatexid_test.go b/generatexid_test.go new file mode 100644 index 0000000..9b5164e --- /dev/null +++ b/generatexid_test.go @@ -0,0 +1,29 @@ +package dhcp4client_test + +import ( + "bytes" + "math/rand" + "testing" + + "github.com/d2g/dhcp4client" +) + +func Test_GenerateXID(t *testing.T) { + //Set the math seed so we always get the same result. + rand.Seed(1) + + crypto_messageid := make([]byte, 4) + dhcp4client.CryptoGenerateXID(crypto_messageid) + + t.Logf("Crypto Token: %v", crypto_messageid) + + math_messageid := make([]byte, 4) + dhcp4client.MathGenerateXID(math_messageid) + + //Math token shouldn't change as we don't seed it. + if !bytes.Equal(math_messageid, []byte{82, 253, 252, 7}) { + t.Errorf("Math Token was %v, expected %v", math_messageid, []byte{82, 253, 252, 7}) + t.Fail() + } + +} diff --git a/init.go b/init.go deleted file mode 100644 index 67ae8a3..0000000 --- a/init.go +++ /dev/null @@ -1,10 +0,0 @@ -package dhcp4client - -import ( - "math/rand" - "time" -) - -func init() { - rand.Seed(time.Now().Unix()) -}