From 9c6932b97d348413e39414f9d32a90a918e10f9b Mon Sep 17 00:00:00 2001 From: Andrea Barberio Date: Mon, 28 Jan 2019 00:53:04 +0000 Subject: [PATCH] dhcpv4: moved client into dhcpv4/client4 --- dhcpv4/async/client.go | 9 ++++---- dhcpv4/async/client_test.go | 7 ++++--- dhcpv4/bsdp/bsdp.go | 3 ++- dhcpv4/bsdp/bsdp_test.go | 15 +++++++------- dhcpv4/bsdp/client.go | 13 ++++++------ dhcpv4/{ => client4}/client.go | 27 ++++++++++++------------ dhcpv4/{ => client4}/defaults.go | 2 +- dhcpv4/{ => server4}/server.go | 8 +++++--- dhcpv4/{ => server4}/server_test.go | 32 +++++++++++++++-------------- netboot/netboot.go | 3 ++- 10 files changed, 65 insertions(+), 54 deletions(-) rename dhcpv4/{ => client4}/client.go (92%) rename dhcpv4/{ => client4}/defaults.go (73%) rename dhcpv4/{ => server4}/server.go (95%) rename dhcpv4/{ => server4}/server_test.go (76%) diff --git a/dhcpv4/async/client.go b/dhcpv4/async/client.go index 617c7115..4c2d3c18 100644 --- a/dhcpv4/async/client.go +++ b/dhcpv4/async/client.go @@ -7,8 +7,9 @@ import ( "sync" "time" - "github.com/fanliao/go-promise" + promise "github.com/fanliao/go-promise" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" ) // Default ports @@ -41,8 +42,8 @@ type Client struct { // NewClient creates an asynchronous client func NewClient() *Client { return &Client{ - ReadTimeout: dhcpv4.DefaultReadTimeout, - WriteTimeout: dhcpv4.DefaultWriteTimeout, + ReadTimeout: client4.DefaultReadTimeout, + WriteTimeout: client4.DefaultWriteTimeout, } } @@ -159,7 +160,7 @@ func (c *Client) receive(_ *dhcpv4.DHCPv4) { c.connection.SetReadDeadline(time.Now().Add(c.ReadTimeout)) for { - buffer := make([]byte, dhcpv4.MaxUDPReceivedPacketSize) + buffer := make([]byte, client4.MaxUDPReceivedPacketSize) n, _, _, _, err := c.connection.ReadMsgUDP(buffer, oobdata) if err != nil { if err, ok := err.(net.Error); !ok || !err.Timeout() { diff --git a/dhcpv4/async/client_test.go b/dhcpv4/async/client_test.go index 7fa0e9e7..b134afe7 100644 --- a/dhcpv4/async/client_test.go +++ b/dhcpv4/async/client_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" "github.com/stretchr/testify/require" ) @@ -19,7 +20,7 @@ func serve(ctx context.Context, addr *net.UDPAddr, response *dhcpv4.DHCPv4) erro go func() { defer conn.Close() oobdata := []byte{} - buffer := make([]byte, dhcpv4.MaxUDPReceivedPacketSize) + buffer := make([]byte, client4.MaxUDPReceivedPacketSize) for { select { case <-ctx.Done(): @@ -48,8 +49,8 @@ func serve(ctx context.Context, addr *net.UDPAddr, response *dhcpv4.DHCPv4) erro func TestNewClient(t *testing.T) { c := NewClient() require.NotNil(t, c) - require.Equal(t, c.ReadTimeout, dhcpv4.DefaultReadTimeout) - require.Equal(t, c.ReadTimeout, dhcpv4.DefaultWriteTimeout) + require.Equal(t, c.ReadTimeout, client4.DefaultReadTimeout) + require.Equal(t, c.ReadTimeout, client4.DefaultWriteTimeout) } func TestOpenInvalidAddrFailes(t *testing.T) { diff --git a/dhcpv4/bsdp/bsdp.go b/dhcpv4/bsdp/bsdp.go index c9f7c26d..df44af91 100644 --- a/dhcpv4/bsdp/bsdp.go +++ b/dhcpv4/bsdp/bsdp.go @@ -6,6 +6,7 @@ import ( "net" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" ) // MaxDHCPMessageSize is the size set in DHCP option 57 (DHCP Maximum Message Size). @@ -39,7 +40,7 @@ func ParseBootImageListFromAck(ack *dhcpv4.DHCPv4) ([]BootImage, error) { } func needsReplyPort(replyPort uint16) bool { - return replyPort != 0 && replyPort != dhcpv4.ClientPort + return replyPort != 0 && replyPort != client4.ClientPort } // MessageTypeFromPacket extracts the BSDP message type (LIST, SELECT) from the diff --git a/dhcpv4/bsdp/bsdp_test.go b/dhcpv4/bsdp/bsdp_test.go index 05cd85c0..d5e400b3 100644 --- a/dhcpv4/bsdp/bsdp_test.go +++ b/dhcpv4/bsdp/bsdp_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/require" ) @@ -57,7 +58,7 @@ func TestParseBootImageListFromAckNoVendorOption(t *testing.T) { func TestNeedsReplyPort(t *testing.T) { require.True(t, needsReplyPort(123)) require.False(t, needsReplyPort(0)) - require.False(t, needsReplyPort(dhcpv4.ClientPort)) + require.False(t, needsReplyPort(client4.ClientPort)) } func TestNewInformList_NoReplyPort(t *testing.T) { @@ -214,13 +215,13 @@ func TestInformSelectForAck_ReplyPort(t *testing.T) { } func TestNewReplyForInformList_NoDefaultImage(t *testing.T) { - inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, dhcpv4.ClientPort) + inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, client4.ClientPort) _, err := NewReplyForInformList(inform, ReplyConfig{}) require.Error(t, err) } func TestNewReplyForInformList_NoImages(t *testing.T) { - inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, dhcpv4.ClientPort) + inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, client4.ClientPort) fakeImage := BootImage{ ID: BootImageID{ImageType: BootImageTypeMacOSX}, } @@ -238,7 +239,7 @@ func TestNewReplyForInformList_NoImages(t *testing.T) { } func TestNewReplyForInformList(t *testing.T) { - inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, dhcpv4.ClientPort) + inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, client4.ClientPort) images := []BootImage{ BootImage{ ID: BootImageID{ @@ -292,13 +293,13 @@ func TestNewReplyForInformList(t *testing.T) { } func TestNewReplyForInformSelect_NoSelectedImage(t *testing.T) { - inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, dhcpv4.ClientPort) + inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, client4.ClientPort) _, err := NewReplyForInformSelect(inform, ReplyConfig{}) require.Error(t, err) } func TestNewReplyForInformSelect_NoImages(t *testing.T) { - inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, dhcpv4.ClientPort) + inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, client4.ClientPort) fakeImage := BootImage{ ID: BootImageID{ImageType: BootImageTypeMacOSX}, } @@ -316,7 +317,7 @@ func TestNewReplyForInformSelect_NoImages(t *testing.T) { } func TestNewReplyForInformSelect(t *testing.T) { - inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, dhcpv4.ClientPort) + inform, _ := NewInformList(net.HardwareAddr{1, 2, 3, 4, 5, 6}, net.IP{1, 2, 3, 4}, client4.ClientPort) images := []BootImage{ BootImage{ ID: BootImageID{ diff --git a/dhcpv4/bsdp/client.go b/dhcpv4/bsdp/client.go index e8ca2ca8..173291e5 100644 --- a/dhcpv4/bsdp/client.go +++ b/dhcpv4/bsdp/client.go @@ -4,18 +4,19 @@ import ( "errors" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" ) // Client represents a BSDP client that can perform BSDP exchanges via the // broadcast address. type Client struct { - dhcpv4.Client + client4.Client } // NewClient constructs a new client with default read and write timeouts from // dhcpv4.Client. func NewClient() *Client { - return &Client{Client: dhcpv4.Client{}} + return &Client{Client: client4.Client{}} } // Exchange runs a full BSDP exchange (Inform[list], Ack, Inform[select], @@ -24,17 +25,17 @@ func (c *Client) Exchange(ifname string) ([]*Packet, error) { conversation := make([]*Packet, 0) // Get our file descriptor for the broadcast socket. - sendFd, err := dhcpv4.MakeBroadcastSocket(ifname) + sendFd, err := client4.MakeBroadcastSocket(ifname) if err != nil { return conversation, err } - recvFd, err := dhcpv4.MakeListeningSocket(ifname) + recvFd, err := client4.MakeListeningSocket(ifname) if err != nil { return conversation, err } // INFORM[LIST] - informList, err := NewInformListForInterface(ifname, dhcpv4.ClientPort) + informList, err := NewInformListForInterface(ifname, client4.ClientPort) if err != nil { return conversation, err } @@ -59,7 +60,7 @@ func (c *Client) Exchange(ifname string) ([]*Packet, error) { } // INFORM[SELECT] - informSelect, err := InformSelectForAck(PacketFor(ackForList), dhcpv4.ClientPort, bootImages[0]) + informSelect, err := InformSelectForAck(PacketFor(ackForList), client4.ClientPort, bootImages[0]) if err != nil { return conversation, err } diff --git a/dhcpv4/client.go b/dhcpv4/client4/client.go similarity index 92% rename from dhcpv4/client.go rename to dhcpv4/client4/client.go index ad80b345..fca9c09c 100644 --- a/dhcpv4/client.go +++ b/dhcpv4/client4/client.go @@ -1,4 +1,4 @@ -package dhcpv4 +package client4 import ( "encoding/binary" @@ -9,6 +9,7 @@ import ( "reflect" "time" + "github.com/insomniacslk/dhcp/dhcpv4" "golang.org/x/net/ipv4" "golang.org/x/sys/unix" ) @@ -88,7 +89,7 @@ func makeRawSocket(ifname string) (int, error) { if err != nil { return fd, err } - err = BindToInterface(fd, ifname) + err = dhcpv4.BindToInterface(fd, ifname) if err != nil { return fd, err } @@ -179,8 +180,8 @@ func (c *Client) getRemoteUDPAddr() (*net.UDPAddr, error) { // ordered as Discovery, Offer, Request and Acknowledge. In case of errors, an // error is returned, and the list of DHCPv4 objects will be shorted than 4, // containing all the sent and received DHCPv4 messages. -func (c *Client) Exchange(ifname string, modifiers ...Modifier) ([]*DHCPv4, error) { - conversation := make([]*DHCPv4, 0) +func (c *Client) Exchange(ifname string, modifiers ...dhcpv4.Modifier) ([]*dhcpv4.DHCPv4, error) { + conversation := make([]*dhcpv4.DHCPv4, 0) raddr, err := c.getRemoteUDPAddr() if err != nil { return nil, err @@ -220,28 +221,28 @@ func (c *Client) Exchange(ifname string, modifiers ...Modifier) ([]*DHCPv4, erro }() // Discover - discover, err := NewDiscoveryForInterface(ifname, modifiers...) + discover, err := dhcpv4.NewDiscoveryForInterface(ifname, modifiers...) if err != nil { return conversation, err } conversation = append(conversation, discover) // Offer - offer, err := c.SendReceive(sfd, rfd, discover, MessageTypeOffer) + offer, err := c.SendReceive(sfd, rfd, discover, dhcpv4.MessageTypeOffer) if err != nil { return conversation, err } conversation = append(conversation, offer) // Request - request, err := NewRequestFromOffer(offer, modifiers...) + request, err := dhcpv4.NewRequestFromOffer(offer, modifiers...) if err != nil { return conversation, err } conversation = append(conversation, request) // Ack - ack, err := c.SendReceive(sfd, rfd, request, MessageTypeAck) + ack, err := c.SendReceive(sfd, rfd, request, dhcpv4.MessageTypeAck) if err != nil { return conversation, err } @@ -253,7 +254,7 @@ func (c *Client) Exchange(ifname string, modifiers ...Modifier) ([]*DHCPv4, erro // SendReceive sends a packet (with some write timeout) and waits for a // response up to some read timeout value. If the message type is not // MessageTypeNone, it will wait for a specific message type -func (c *Client) SendReceive(sendFd, recvFd int, packet *DHCPv4, messageType MessageType) (*DHCPv4, error) { +func (c *Client) SendReceive(sendFd, recvFd int, packet *dhcpv4.DHCPv4, messageType dhcpv4.MessageType) (*dhcpv4.DHCPv4, error) { raddr, err := c.getRemoteUDPAddr() if err != nil { return nil, err @@ -271,7 +272,7 @@ func (c *Client) SendReceive(sendFd, recvFd int, packet *DHCPv4, messageType Mes // a certain amount of time. var ( destination [net.IPv4len]byte - response *DHCPv4 + response *dhcpv4.DHCPv4 ) copy(destination[:], raddr.IP.To4()) remoteAddr := unix.SockaddrInet4{Port: laddr.Port, Addr: destination} @@ -322,7 +323,7 @@ func (c *Client) SendReceive(sendFd, recvFd int, packet *DHCPv4, messageType Mes pLen := int(binary.BigEndian.Uint16(udph[4:6])) payload := buf[iph.Len+8 : iph.Len+8+pLen] - response, innerErr = FromBytes(payload) + response, innerErr = dhcpv4.FromBytes(payload) if innerErr != nil { errs <- innerErr return @@ -332,12 +333,12 @@ func (c *Client) SendReceive(sendFd, recvFd int, packet *DHCPv4, messageType Mes continue } // wait for a response message - if response.OpCode != OpcodeBootReply { + if response.OpCode != dhcpv4.OpcodeBootReply { continue } // if we are not requested to wait for a specific message type, // return what we have - if messageType == MessageTypeNone { + if messageType == dhcpv4.MessageTypeNone { break } // break if it's a reply of the desired type, continue otherwise diff --git a/dhcpv4/defaults.go b/dhcpv4/client4/defaults.go similarity index 73% rename from dhcpv4/defaults.go rename to dhcpv4/client4/defaults.go index 4faec2cc..f2e31f31 100644 --- a/dhcpv4/defaults.go +++ b/dhcpv4/client4/defaults.go @@ -1,4 +1,4 @@ -package dhcpv4 +package client4 const ( ServerPort = 67 diff --git a/dhcpv4/server.go b/dhcpv4/server4/server.go similarity index 95% rename from dhcpv4/server.go rename to dhcpv4/server4/server.go index eed82cfc..5ef4479d 100644 --- a/dhcpv4/server.go +++ b/dhcpv4/server4/server.go @@ -1,4 +1,4 @@ -package dhcpv4 +package server4 import ( "fmt" @@ -6,6 +6,8 @@ import ( "net" "sync" "time" + + "github.com/insomniacslk/dhcp/dhcpv4" ) /* @@ -56,7 +58,7 @@ func main() { // Handler is a type that defines the handler function to be called every time a // valid DHCPv4 message is received -type Handler func(conn net.PacketConn, peer net.Addr, m *DHCPv4) +type Handler func(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) // Server represents a DHCPv4 server object type Server struct { @@ -129,7 +131,7 @@ func (s *Server) ActivateAndServe() error { continue } log.Printf("Handling request from %v", peer) - m, err := FromBytes(rbuf[:n]) + m, err := dhcpv4.FromBytes(rbuf[:n]) if err != nil { log.Printf("Error parsing DHCPv4 request: %v", err) continue diff --git a/dhcpv4/server_test.go b/dhcpv4/server4/server_test.go similarity index 76% rename from dhcpv4/server_test.go rename to dhcpv4/server4/server_test.go index 3cfd4e1d..f6ce18e4 100644 --- a/dhcpv4/server_test.go +++ b/dhcpv4/server4/server_test.go @@ -1,6 +1,6 @@ // +build integration -package dhcpv4 +package server4 import ( "log" @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" "github.com/insomniacslk/dhcp/interfaces" "github.com/stretchr/testify/require" ) @@ -27,26 +29,26 @@ func randPort() int { } // DORAHandler is a server handler suitable for DORA transactions -func DORAHandler(conn net.PacketConn, peer net.Addr, m *DHCPv4) { +func DORAHandler(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) { if m == nil { log.Printf("Packet is nil!") return } - if m.OpCode != OpcodeBootRequest { + if m.OpCode != dhcpv4.OpcodeBootRequest { log.Printf("Not a BootRequest!") return } - reply, err := NewReplyFromRequest(m) + reply, err := dhcpv4.NewReplyFromRequest(m) if err != nil { log.Printf("NewReplyFromRequest failed: %v", err) return } - reply.UpdateOption(OptServerIdentifier(net.IP{1, 2, 3, 4})) + reply.UpdateOption(dhcpv4.OptServerIdentifier(net.IP{1, 2, 3, 4})) switch mt := m.MessageType(); mt { - case MessageTypeDiscover: - reply.UpdateOption(OptMessageType(MessageTypeOffer)) - case MessageTypeRequest: - reply.UpdateOption(OptMessageType(MessageTypeAck)) + case dhcpv4.MessageTypeDiscover: + reply.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer)) + case dhcpv4.MessageTypeRequest: + reply.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck)) default: log.Printf("Unhandled message type: %v", mt) return @@ -59,7 +61,7 @@ func DORAHandler(conn net.PacketConn, peer net.Addr, m *DHCPv4) { // utility function to set up a client and a server instance and run it in // background. The caller needs to call Server.Close() once finished. -func setUpClientAndServer(handler Handler) (*Client, *Server) { +func setUpClientAndServer(handler Handler) (*client4.Client, *Server) { // strong assumption, I know loAddr := net.ParseIP("127.0.0.1") laddr := net.UDPAddr{ @@ -69,7 +71,7 @@ func setUpClientAndServer(handler Handler) (*Client, *Server) { s := NewServer(laddr, handler) go s.ActivateAndServe() - c := NewClient() + c := client4.NewClient() // FIXME this doesn't deal well with raw sockets, the actual 0 will be used // in the UDP header as source port c.LocalAddr = &net.UDPAddr{IP: loAddr, Port: randPort()} @@ -108,12 +110,12 @@ func TestServerActivateAndServe(t *testing.T) { require.NoError(t, err) require.NotEqual(t, 0, len(ifaces)) - xid := TransactionID{0xaa, 0xbb, 0xcc, 0xdd} + xid := dhcpv4.TransactionID{0xaa, 0xbb, 0xcc, 0xdd} hwaddr := net.HardwareAddr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf} - modifiers := []Modifier{ - WithTransactionID(xid), - WithHwAddr(hwaddr), + modifiers := []dhcpv4.Modifier{ + dhcpv4.WithTransactionID(xid), + dhcpv4.WithHwAddr(hwaddr), } conv, err := c.Exchange(ifaces[0].Name, modifiers...) diff --git a/netboot/netboot.go b/netboot/netboot.go index b340046c..15990b13 100644 --- a/netboot/netboot.go +++ b/netboot/netboot.go @@ -7,6 +7,7 @@ import ( "time" "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" "github.com/insomniacslk/dhcp/dhcpv6" "github.com/insomniacslk/dhcp/dhcpv6/client6" ) @@ -58,7 +59,7 @@ func RequestNetbootv4(ifname string, timeout time.Duration, retries int, modifie modifiers = append(modifiers, dhcpv4.WithNetboot) for i := 0; i <= retries; i++ { log.Printf("sending request, attempt #%d", i+1) - client := dhcpv4.NewClient() + client := client4.NewClient() client.ReadTimeout = timeout conversation, err = client.Exchange(ifname, modifiers...) if err != nil {