From 1e4d47fc35cc4154abcdf61f4aeb218eb39e8ccb Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Thu, 27 Sep 2018 11:04:14 -0400 Subject: [PATCH 01/10] Fix vendor regression in dhcp4server --- Godeps/Godeps.json | 6 +- .../d2g/dhcp4server/leasepool/lease_test.go | 51 +++ .../leasepool/memorypool/memorypool.go | 2 +- .../leasepool/memorypool/memorypool_test.go | 56 +++ vendor/github.com/d2g/dhcp4server/server.go | 22 +- .../github.com/d2g/dhcp4server/server_test.go | 426 ++++++++++++++++++ 6 files changed, 555 insertions(+), 8 deletions(-) create mode 100644 vendor/github.com/d2g/dhcp4server/leasepool/lease_test.go create mode 100644 vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool_test.go create mode 100644 vendor/github.com/d2g/dhcp4server/server_test.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 88795fab..ffd50756 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -134,15 +134,15 @@ }, { "ImportPath": "github.com/d2g/dhcp4server", - "Rev": "1b74244053681c90de5cf1af3d6b5c93b74e3abb" + "Rev": "477b11cea4dcc56af002849238d4f9c1e093c744" }, { "ImportPath": "github.com/d2g/dhcp4server/leasepool", - "Rev": "1b74244053681c90de5cf1af3d6b5c93b74e3abb" + "Rev": "477b11cea4dcc56af002849238d4f9c1e093c744" }, { "ImportPath": "github.com/d2g/dhcp4server/leasepool/memorypool", - "Rev": "1b74244053681c90de5cf1af3d6b5c93b74e3abb" + "Rev": "477b11cea4dcc56af002849238d4f9c1e093c744" }, { "ImportPath": "github.com/j-keck/arping", diff --git a/vendor/github.com/d2g/dhcp4server/leasepool/lease_test.go b/vendor/github.com/d2g/dhcp4server/leasepool/lease_test.go new file mode 100644 index 00000000..2a2e9658 --- /dev/null +++ b/vendor/github.com/d2g/dhcp4server/leasepool/lease_test.go @@ -0,0 +1,51 @@ +package leasepool + +import ( + "encoding/json" + "net" + "testing" + "time" +) + +/* + * The Leases are Marshalled and Unmarshalled for storage. + * I JSON Marshal these for gvklite + */ +func TestMarshaling(test *testing.T) { + var err error + + startLease := Lease{} + startLease.IP = net.IPv4(192, 168, 0, 1) + startLease.Hostname = "ExampleHostname" + startLease.Status = Active + startLease.Expiry = time.Now() + startLease.MACAddress, err = net.ParseMAC("01:23:45:67:89:ab") + if err != nil { + test.Error("Error Parsing Mac Address:" + err.Error()) + } + + byteStartLease, err := json.Marshal(startLease) + if err != nil { + test.Error("Error Marshaling to JSON:" + err.Error()) + } + + test.Log("StartLease As JSON:" + string(byteStartLease)) + + endLease := Lease{} + err = json.Unmarshal(byteStartLease, &endLease) + if err != nil { + test.Error("Error Unmarshaling to JSON:" + err.Error()) + } + + test.Logf("End Lease Object:%v\n", endLease) + + if !startLease.Equal(endLease) { + byteEndLease, err := json.Marshal(endLease) + if err != nil { + test.Error("Can't Marshal End Lease For Debuging:" + err.Error()) + } + test.Log("End Lease as JSON:" + string(byteEndLease)) + test.Error("Starting Lease Doesn't Match End Lease") + } + +} diff --git a/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool.go b/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool.go index 57aa3730..29ff97c2 100644 --- a/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool.go +++ b/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool.go @@ -104,7 +104,7 @@ func (t *MemoryPool) GetNextFreeLease() (bool, leasepool.Lease, error) { defer t.poolLock.Unlock() //Loop Through the elements backwards. - for i := (len(t.pool) - 1); i > 0; i-- { + for i := (len(t.pool) - 1); i >= 0; i-- { //If the Lease Is Free if t.pool[i].Status == leasepool.Free { //Take the Element diff --git a/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool_test.go b/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool_test.go new file mode 100644 index 00000000..6e699d66 --- /dev/null +++ b/vendor/github.com/d2g/dhcp4server/leasepool/memorypool/memorypool_test.go @@ -0,0 +1,56 @@ +package memorypool + +import ( + "github.com/d2g/dhcp4" + "github.com/d2g/dhcp4server/leasepool" + "net" + "testing" +) + +func TestLeaseCycle(test *testing.T) { + myMemoryLeasePool := MemoryPool{} + + //Lets add a list of IPs to the pool these will be served to the clients so make sure they work for you. + // So Create Array of IPs 192.168.1.1 to 192.168.1.30 + for i := 0; i < 30; i++ { + err := myMemoryLeasePool.AddLease(leasepool.Lease{IP: dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i)}) + if err != nil { + test.Error("Error Creating Lease:" + err.Error()) + } + } + + for i := 0; i < 30; i++ { + hasLease, iLease, err := myMemoryLeasePool.GetNextFreeLease() + if err != nil { + test.Error("Error Getting Lease:" + err.Error()) + } + if !hasLease { + test.Error("Failed to get get lease (none free?)") + } + + if !dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i).Equal(iLease.IP) { + test.Error("Expected Lease:" + dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i).String() + " Received:" + iLease.IP.String()) + } + } +} + +func TestSingleLease(test *testing.T) { + myMemoryLeasePool := MemoryPool{} + + err := myMemoryLeasePool.AddLease(leasepool.Lease{IP: dhcp4.IPAdd(net.IPv4(192, 168, 1, 5), 0)}) + if err != nil { + test.Error("Error Creating Lease:" + err.Error()) + } + + hasLease, iLease, err := myMemoryLeasePool.GetNextFreeLease() + if err != nil { + test.Error("Error Getting Lease:" + err.Error()) + } + if !hasLease { + test.Error("Failed to get get lease (none free?)") + } + + if !dhcp4.IPAdd(net.IPv4(192, 168, 1, 5), 0).Equal(iLease.IP) { + test.Error("Expected Lease:" + dhcp4.IPAdd(net.IPv4(192, 168, 1, 5), 0).String() + " Received:" + iLease.IP.String()) + } +} diff --git a/vendor/github.com/d2g/dhcp4server/server.go b/vendor/github.com/d2g/dhcp4server/server.go index c3e5250c..9a4b57ff 100644 --- a/vendor/github.com/d2g/dhcp4server/server.go +++ b/vendor/github.com/d2g/dhcp4server/server.go @@ -5,6 +5,7 @@ import ( "errors" "log" "net" + "sync/atomic" "time" "github.com/d2g/dhcp4" @@ -36,7 +37,7 @@ type Server struct { leasePool leasepool.LeasePool //Lease Pool Manager //Used to Gracefully Close the Server - shutdown bool + shutdown uint32 //Listeners & Response Connection. connection *ipv4.PacketConn } @@ -178,7 +179,7 @@ func (s *Server) ListenAndServe() error { for { ListenForDHCPPackets: - if s.shutdown { + if s.shouldShutdown() { return nil } @@ -191,6 +192,13 @@ func (s *Server) ListenAndServe() error { switch v := err.(type) { case *net.OpError: + // If we've been signaled to shut down, ignore + // the "use of closed network connection" error + // since the connection was closed by the + // shutdown request + if s.shouldShutdown() { + return nil + } if v.Timeout() { goto ListenForDHCPPackets } @@ -204,7 +212,8 @@ func (s *Server) ListenAndServe() error { } } - log.Println("Debug: Unexpect Error from Connection Read From:" + err.Error()) + log.Printf("Debug: Unexpect Error from Connection Read From: %v\n", err) + log.Printf("Debug: err type %T %#v\n", err, err) return err } @@ -527,7 +536,12 @@ func (s *Server) GetLease(packet dhcp4.Packet) (found bool, lease leasepool.Leas * Shutdown The Server Gracefully */ func (s *Server) Shutdown() { - s.shutdown = true + atomic.StoreUint32(&s.shutdown, 1) + s.connection.Close() +} + +func (s *Server) shouldShutdown() bool { + return atomic.LoadUint32(&s.shutdown) == 1 } /* diff --git a/vendor/github.com/d2g/dhcp4server/server_test.go b/vendor/github.com/d2g/dhcp4server/server_test.go new file mode 100644 index 00000000..0080b84c --- /dev/null +++ b/vendor/github.com/d2g/dhcp4server/server_test.go @@ -0,0 +1,426 @@ +package dhcp4server_test + +import ( + "bytes" + "encoding/binary" + "log" + "net" + "sync" + "testing" + "time" + + "github.com/d2g/dhcp4" + "github.com/d2g/dhcp4client" + "github.com/d2g/dhcp4server" + "github.com/d2g/dhcp4server/leasepool" + "github.com/d2g/dhcp4server/leasepool/memorypool" + "github.com/d2g/hardwareaddr" +) + +/* + * Example Server :D + */ +func ExampleServer() { + + //Create a Lease Pool We're going to use a memory pool + //Remember the memory is cleared on restart so you will reissue the same IP Addresses. + myMemoryLeasePool := memorypool.MemoryPool{} + + //Lets add a list of IPs to the pool these will be served to the clients so make sure they work for you. + // So Create Array of IPs 192.168.1.1 to 192.168.1.30 + for i := 0; i < 30; i++ { + err := myMemoryLeasePool.AddLease(leasepool.Lease{IP: dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i)}) + if err != nil { + log.Fatalln("Error Adding IP to pool:" + err.Error()) + } + } + + // We set the port numbers to over 1024 (1067 & 1068) as the automated test don't have root access + tServer, err := dhcp4server.New( + net.IPv4(192, 168, 1, 201), + &myMemoryLeasePool, + dhcp4server.SetLocalAddr(net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 1067}), + dhcp4server.SetRemoteAddr(net.UDPAddr{IP: net.IPv4bcast, Port: 1068}), + ) + if err != nil { + log.Fatalln("Error Configuring Server:" + err.Error()) + } + + //Start the Server... + err = tServer.ListenAndServe() + if err != nil { + log.Fatalln("Error Starting Server:" + err.Error()) + } +} + +/* + * Test Discovering a Lease That's not Within Our Lease Range. + * This Happens When a devce switches network. + * Example: Mobile Phone on Mobile internet Has IP 100.123.123.123 Switch To Home Wifi + * The device requests 100.123.123.123 on Home Wifi which is out of range... + */ +func TestDiscoverOutOfRangeLease(test *testing.T) { + //Setup the Server + myServer, err := dhcp4server.New( + net.IPv4(192, 168, 1, 201), + getTestLeasePool(), + dhcp4server.SetLocalAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1067}), + dhcp4server.SetRemoteAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1068}), + ) + if err != nil { + test.Error("Error: Can't Configure Server " + err.Error()) + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + err := myServer.ListenAndServe() + if err != nil { + log.Fatalln("Error Starting Server:" + err.Error()) + } + }() + + time.Sleep(time.Duration(5) * time.Second) + + //Generate Hardware Address + HardwareMACAddress, err := hardwareaddr.GenerateEUI48() + if err != nil { + test.Error("Error: Can't Generate Valid MACAddress" + err.Error()) + } + + //Lets Be A Client + + //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(127, 0, 0, 1), Port: 1068}), dhcp4client.SetRemoteAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1067})) + if err != nil { + test.Error("Client Conection Generation:" + err.Error()) + } + + client, err := dhcp4client.New(dhcp4client.HardwareAddr(HardwareMACAddress), dhcp4client.Connection(c)) + defer client.Close() + if err != nil { + test.Error("Conection Error:" + err.Error()) + } + + discoveryPacket := client.DiscoverPacket() + discoveryPacket.SetCIAddr(net.IPv4(100, 102, 96, 123)) + discoveryPacket.PadToMinSize() + + err = client.SendPacket(discoveryPacket) + if err != nil { + test.Error("Error: Sending Discover Packet" + err.Error()) + } + + test.Log("--Discovery Packet--") + test.Logf("Client IP : %v\n", discoveryPacket.CIAddr().String()) + test.Logf("Your IP : %v\n", discoveryPacket.YIAddr().String()) + test.Logf("Server IP : %v\n", discoveryPacket.SIAddr().String()) + test.Logf("Gateway IP: %v\n", discoveryPacket.GIAddr().String()) + test.Logf("Client Mac: %v\n", discoveryPacket.CHAddr().String()) + + if !bytes.Equal(discoveryPacket.CHAddr(), HardwareMACAddress) { + test.Error("MACAddresses Don't Match??") + } + + offerPacket, err := client.GetOffer(&discoveryPacket) + if err != nil { + test.Error("Error Getting Offer:" + err.Error()) + } + + test.Log("--Offer Packet--") + test.Logf("Client IP : %v\n", offerPacket.CIAddr().String()) + test.Logf("Your IP : %v\n", offerPacket.YIAddr().String()) + test.Logf("Server IP : %v\n", offerPacket.SIAddr().String()) + test.Logf("Gateway IP: %v\n", offerPacket.GIAddr().String()) + test.Logf("Client Mac: %v\n", offerPacket.CHAddr().String()) + + requestPacket, err := client.SendRequest(&offerPacket) + if err != nil { + test.Error("Error Sending Request:" + err.Error()) + } + + test.Log("--Request Packet--") + test.Logf("Client IP : %v\n", requestPacket.CIAddr().String()) + test.Logf("Your IP : %v\n", requestPacket.YIAddr().String()) + test.Logf("Server IP : %v\n", requestPacket.SIAddr().String()) + test.Logf("Gateway IP: %v\n", requestPacket.GIAddr().String()) + test.Logf("Client Mac: %v\n", requestPacket.CHAddr().String()) + + acknowledgement, err := client.GetAcknowledgement(&requestPacket) + if err != nil { + test.Error("Error Getting Acknowledgement:" + err.Error()) + } + + test.Log("--Acknowledgement Packet--") + test.Logf("Client IP : %v\n", acknowledgement.CIAddr().String()) + test.Logf("Your IP : %v\n", acknowledgement.YIAddr().String()) + test.Logf("Server IP : %v\n", acknowledgement.SIAddr().String()) + test.Logf("Gateway IP: %v\n", acknowledgement.GIAddr().String()) + test.Logf("Client Mac: %v\n", acknowledgement.CHAddr().String()) + + acknowledgementOptions := acknowledgement.ParseOptions() + if dhcp4.MessageType(acknowledgementOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.ACK { + test.Error("Didn't get ACK?:" + err.Error()) + } + + test.Log("Shutting Down Server") + myServer.Shutdown() + wg.Wait() +} + +/* + * Try Renewing A Lease From A Different Network. + */ +func TestRequestOutOfRangeLease(test *testing.T) { + //Setup the Server + myServer, err := dhcp4server.New( + net.IPv4(192, 168, 1, 201), + getTestLeasePool(), + dhcp4server.SetLocalAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1067}), + dhcp4server.SetRemoteAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1068}), + ) + if err != nil { + test.Error("Error: Can't Configure Server " + err.Error()) + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + err := myServer.ListenAndServe() + if err != nil { + log.Fatalln("Error Starting Server:" + err.Error()) + } + }() + + //Sleep some so the server starts.... + time.Sleep(time.Duration(5) * time.Second) + + //Generate Hardware Address + HardwareMACAddress, err := hardwareaddr.GenerateEUI48() + if err != nil { + test.Error("Error: Can't Generate Valid MACAddress" + err.Error()) + } + + HardwareMACAddress, err = net.ParseMAC("58-94-6B-73-57-0C") + if err != nil { + log.Printf("MAC Error:%v\n", err) + } + + //Lets Be A Client + c, err := dhcp4client.NewInetSock(dhcp4client.SetLocalAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1068}), dhcp4client.SetRemoteAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1067})) + if err != nil { + test.Error("Client Conection Generation:" + err.Error()) + } + + client, err := dhcp4client.New(dhcp4client.HardwareAddr(HardwareMACAddress), dhcp4client.Connection(c)) + defer client.Close() + + if err != nil { + test.Error("Conection Error:" + err.Error()) + } + + //Create a dummy offer packet + offerPacket := client.DiscoverPacket() + + offerPacket.SetCIAddr(net.IPv4(100, 102, 96, 123)) + offerPacket.SetSIAddr(net.IPv4(192, 168, 1, 201)) + offerPacket.SetYIAddr(net.IPv4(100, 102, 96, 123)) + offerPacket.AddOption(dhcp4.OptionDHCPMessageType, []byte{byte(dhcp4.Offer)}) + + requestPacket, err := client.SendRequest(&offerPacket) + if err != nil { + test.Error("Error Sending Request:" + err.Error()) + } + + test.Log("--Request Packet--") + test.Logf("Client IP : %v\n", requestPacket.CIAddr().String()) + test.Logf("Your IP : %v\n", requestPacket.YIAddr().String()) + test.Logf("Server IP : %v\n", requestPacket.SIAddr().String()) + test.Logf("Gateway IP: %v\n", requestPacket.GIAddr().String()) + test.Logf("Client Mac: %v\n", requestPacket.CHAddr().String()) + + acknowledgement, err := client.GetAcknowledgement(&requestPacket) + if err != nil { + test.Error("Error Getting Acknowledgement:" + err.Error()) + } + + test.Log("--Acknowledgement Packet--") + test.Logf("Client IP : %v\n", acknowledgement.CIAddr().String()) + test.Logf("Your IP : %v\n", acknowledgement.YIAddr().String()) + test.Logf("Server IP : %v\n", acknowledgement.SIAddr().String()) + test.Logf("Gateway IP: %v\n", acknowledgement.GIAddr().String()) + test.Logf("Client Mac: %v\n", acknowledgement.CHAddr().String()) + + acknowledgementOptions := acknowledgement.ParseOptions() + if len(acknowledgementOptions[dhcp4.OptionDHCPMessageType]) <= 0 || dhcp4.MessageType(acknowledgementOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.NAK { + test.Errorf("Didn't get NAK got DHCP4 Message Type:%v\n", dhcp4.MessageType(acknowledgementOptions[dhcp4.OptionDHCPMessageType][0])) + } + + test.Log("Shutting Down Server") + myServer.Shutdown() + wg.Wait() +} + +/* + * + */ +func TestConsumeLeases(test *testing.T) { + //Setup the Server + myServer, err := dhcp4server.New( + net.IPv4(127, 0, 0, 1), + getTestLeasePool(), + ) + if err != nil { + test.Error("Error: Can't Configure Server " + err.Error()) + } + + // Setup A Client + // Although We Won't send the packets over the network we'll use the client to create the requests. + c, err := dhcp4client.NewInetSock(dhcp4client.SetLocalAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1068}), dhcp4client.SetRemoteAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1067})) + if err != nil { + test.Error("Client Conection Generation:" + err.Error()) + } + + client, err := dhcp4client.New(dhcp4client.Connection(c)) + if err != nil { + test.Error("Error: Can't Configure Client " + err.Error()) + } + defer client.Close() + + for i := 0; i < 30; i++ { + //Generate Hardware Address + HardwareMACAddress, err := hardwareaddr.GenerateEUI48() + if err != nil { + test.Error("Error: Can't Generate Valid MACAddress" + err.Error()) + } + + client.SetOption(dhcp4client.HardwareAddr(HardwareMACAddress)) + test.Log("MAC:" + HardwareMACAddress.String()) + + discovery := client.DiscoverPacket() + + //Run the Discovery On the Server + offer, err := myServer.ServeDHCP(discovery) + _, err = myServer.ServeDHCP(discovery) + if err != nil { + test.Error("Discovery Error:" + err.Error()) + } + + request := client.RequestPacket(&offer) + acknowledgement, err := myServer.ServeDHCP(request) + if err != nil { + test.Error("Acknowledge Error:" + err.Error()) + } + + test.Logf("Received Lease:%v\n", acknowledgement.YIAddr().String()) + if !dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i).Equal(acknowledgement.YIAddr()) { + test.Error("Expected IP:" + dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i).String() + " Received:" + acknowledgement.YIAddr().String()) + } + + //How long the lease is for? + acknowledgementOptions := acknowledgement.ParseOptions() + if len(acknowledgementOptions) > 0 { + test.Logf("Lease Options:%v\n", acknowledgementOptions) + if acknowledgementOptions[dhcp4.OptionIPAddressLeaseTime] != nil { + var result uint32 + buf := bytes.NewBuffer(acknowledgementOptions[dhcp4.OptionIPAddressLeaseTime]) + binary.Read(buf, binary.BigEndian, &result) + test.Logf("Lease Time (Seconds):%d\n", result) + } + } else { + test.Errorf("Lease:\"%v\" Has No Options\n", acknowledgement.YIAddr()) + } + } +} + +/* + * Benchmark the ServeDHCP Function + */ +func BenchmarkServeDHCP(test *testing.B) { + //Create a Lease Pool We're going to use a memory pool + //Remember the memory is cleared on restart so you will reissue the same IP Addresses. + myMemoryLeasePool := memorypool.MemoryPool{} + + //Lets add a list of IPs to the pool these will be served to the clients so make sure they work for you. + // So Create Array of IPs 192.168.1.1 to 192.168.1.30 + for i := 0; i < test.N; i++ { + err := myMemoryLeasePool.AddLease(leasepool.Lease{IP: dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i)}) + if err != nil { + log.Fatalln("Error Adding IP to pool:" + err.Error()) + } + } + + //Setup the Server + myServer, err := dhcp4server.New( + net.IPv4(127, 0, 0, 1), + &myMemoryLeasePool, + ) + if err != nil { + test.Error("Error: Can't Configure Server " + err.Error()) + } + + //Setup A Client + // Although We Won't send the packets over the network we'll use the client to create the requests. + c, err := dhcp4client.NewInetSock(dhcp4client.SetLocalAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1068}), dhcp4client.SetRemoteAddr(net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1067})) + if err != nil { + test.Error("Client Conection Generation:" + err.Error()) + } + + client, err := dhcp4client.New(dhcp4client.Connection(c)) + if err != nil { + test.Error("Error: Can't Configure Client " + err.Error()) + } + defer client.Close() + + test.ResetTimer() + + for i := 0; i < test.N; i++ { + test.StopTimer() + //Generate Hardware Address + HardwareMACAddress, err := hardwareaddr.GenerateEUI48() + if err != nil { + test.Error("Error: Can't Generate Valid MACAddress" + err.Error()) + } + + client.SetOption(dhcp4client.HardwareAddr(HardwareMACAddress)) + discovery := client.DiscoverPacket() + + //Run the Discovery On the Server + test.StartTimer() + offer, err := myServer.ServeDHCP(discovery) + if err != nil { + test.Error("Discovery Error:" + err.Error()) + } + + if len(offer) == 0 { + test.Error("No Valid Offer") + } else { + request := client.RequestPacket(&offer) + _, err := myServer.ServeDHCP(request) + if err != nil { + test.Error("Acknowledge Error:" + err.Error()) + } + + } + } +} + +func getTestLeasePool() *memorypool.MemoryPool { + //Create a Lease Pool We're going to use a memory pool + //Remember the memory is cleared on restart so you will reissue the same IP Addresses. + myMemoryLeasePool := memorypool.MemoryPool{} + + //Lets add a list of IPs to the pool these will be served to the clients so make sure they work for you. + // So Create Array of IPs 192.168.1.1 to 192.168.1.30 + for i := 0; i < 30; i++ { + err := myMemoryLeasePool.AddLease(leasepool.Lease{IP: dhcp4.IPAdd(net.IPv4(192, 168, 1, 1), i)}) + if err != nil { + log.Fatalln("Error Adding IP to pool:" + err.Error()) + } + } + return &myMemoryLeasePool +} From 66837d6f3b7817c840e8fcec162a8e28d1aa5c60 Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Mon, 1 Oct 2018 16:12:07 -0400 Subject: [PATCH 02/10] Remove -p from test.sh Running ginkgo tests in parallel causes problems with dhcp_test.go. BeforeEach() is run once for each spec before any actual dhcp test starts. This results in setting up two dhcp4servers that run concurrently. Both try to Listen and use unix socketPath file /run/cni/dhcp.sock at the same time. AfterEach() for one test runs when test completes, deleting /run/cni/dhcp.sock. But other test still needs the file resulting in test failing. Often, the next dhcp test hasn't started yet. When test does start it waits 15 seconds for dhcp4server to create /run/cni/dhcp.sock (which has just been deleted) so test fails. Other times dhcp tests fail because /run/cni/dhcp.sock is deleted while still being used. --- test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.sh b/test.sh index 0c48852d..ccc1068b 100755 --- a/test.sh +++ b/test.sh @@ -10,7 +10,7 @@ source ./build.sh echo "Running tests" -GINKGO_FLAGS="-p --randomizeAllSpecs --randomizeSuites --failOnPending --progress" +GINKGO_FLAGS="-nodes=1 --randomizeAllSpecs --randomizeSuites --failOnPending --progress" # user has not provided PKG override if [ -z "$PKG" ]; then From 6d3215a256c7298bb637de0fef9a7d79e911ee4f Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Mon, 8 Oct 2018 11:30:01 -0400 Subject: [PATCH 03/10] Allow socket path used by dhcp plugin to be supplied via dhcp ipam configuration Allow socket path to be supplied as flag when starting dhcp daemon --- plugins/ipam/dhcp/daemon.go | 6 +++--- plugins/ipam/dhcp/main.go | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/plugins/ipam/dhcp/daemon.go b/plugins/ipam/dhcp/daemon.go index 2404db8f..fcffd0f8 100644 --- a/plugins/ipam/dhcp/daemon.go +++ b/plugins/ipam/dhcp/daemon.go @@ -127,7 +127,7 @@ func (d *DHCP) clearLease(contID, netName string) { delete(d.leases, contID+netName) } -func getListener() (net.Listener, error) { +func getListener(socketPath string) (net.Listener, error) { l, err := activation.Listeners() if err != nil { return nil, err @@ -151,7 +151,7 @@ func getListener() (net.Listener, error) { } } -func runDaemon(pidfilePath string, hostPrefix string) error { +func runDaemon(pidfilePath string, hostPrefix string, socketPath string) error { // since other goroutines (on separate threads) will change namespaces, // ensure the RPC server does not get scheduled onto those runtime.LockOSThread() @@ -166,7 +166,7 @@ func runDaemon(pidfilePath string, hostPrefix string) error { } } - l, err := getListener() + l, err := getListener(socketPath) if err != nil { return fmt.Errorf("Error getting listener: %v", err) } diff --git a/plugins/ipam/dhcp/main.go b/plugins/ipam/dhcp/main.go index f393dd67..b4dbb235 100644 --- a/plugins/ipam/dhcp/main.go +++ b/plugins/ipam/dhcp/main.go @@ -15,6 +15,7 @@ package main import ( + "encoding/json" "flag" "fmt" "log" @@ -28,18 +29,24 @@ import ( "github.com/containernetworking/cni/pkg/version" ) -const socketPath = "/run/cni/dhcp.sock" +const defaultSocketPath = "/run/cni/defaultdhcp.sock" func main() { if len(os.Args) > 1 && os.Args[1] == "daemon" { var pidfilePath string var hostPrefix string + var socketPath string daemonFlags := flag.NewFlagSet("daemon", flag.ExitOnError) daemonFlags.StringVar(&pidfilePath, "pidfile", "", "optional path to write daemon PID to") daemonFlags.StringVar(&hostPrefix, "hostprefix", "", "optional prefix to netns") + daemonFlags.StringVar(&socketPath, "socketpath", "", "optional dhcp server socketpath") daemonFlags.Parse(os.Args[2:]) - if err := runDaemon(pidfilePath, hostPrefix); err != nil { + if socketPath == "" { + socketPath = defaultSocketPath + } + + if err := runDaemon(pidfilePath, hostPrefix, socketPath); err != nil { log.Printf(err.Error()) os.Exit(1) } @@ -78,7 +85,31 @@ func cmdGet(args *skel.CmdArgs) error { return fmt.Errorf("not implemented") } +type SocketPathConf struct { + DaemonSocketPath string `json:"daemonSocketPath,omitempty"` +} + +type TempNetConf struct { + IPAM SocketPathConf `json:"ipam,omitempty"` +} + +func getSocketPath(stdinData []byte) (string, error) { + conf := TempNetConf{} + if err := json.Unmarshal(stdinData, &conf); err != nil { + return "", fmt.Errorf("error parsing socket path conf: %v", err) + } + if conf.IPAM.DaemonSocketPath == "" { + return defaultSocketPath, nil + } + return conf.IPAM.DaemonSocketPath, nil +} + func rpcCall(method string, args *skel.CmdArgs, result interface{}) error { + socketPath, err := getSocketPath(args.StdinData) + if err != nil { + return fmt.Errorf("error obtaining socketPath: %v", err) + } + client, err := rpc.DialHTTP("unix", socketPath) if err != nil { return fmt.Errorf("error dialing DHCP daemon: %v", err) From 5fd849ac6d4f7a90623e6471b25090a91ca65fa5 Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Mon, 8 Oct 2018 11:31:03 -0400 Subject: [PATCH 04/10] Use tempDir in socket path for ginkgo parallelization --- plugins/ipam/dhcp/dhcp_test.go | 36 +++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/plugins/ipam/dhcp/dhcp_test.go b/plugins/ipam/dhcp/dhcp_test.go index 101726e0..2f7d3cec 100644 --- a/plugins/ipam/dhcp/dhcp_test.go +++ b/plugins/ipam/dhcp/dhcp_test.go @@ -16,9 +16,11 @@ package main import ( "fmt" + "io/ioutil" "net" "os" "os/exec" + "path/filepath" "sync" "time" @@ -38,6 +40,15 @@ import ( . "github.com/onsi/gomega" ) +func getTmpDir() (string, error) { + tmpDir, err := ioutil.TempDir("/run/cni", "dhcp") + if err == nil { + tmpDir = filepath.ToSlash(tmpDir) + } + + return tmpDir, err +} + func dhcpServerStart(netns ns.NetNS, leaseIP, serverIP net.IP, stopCh <-chan bool) (*sync.WaitGroup, error) { // Add the expected IP to the pool lp := memorypool.MemoryPool{} @@ -99,6 +110,10 @@ const ( pidfilePath string = "/var/run/cni/dhcp-client.pid" ) +var socketPath string +var tmpDir string +var err error + var _ = BeforeSuite(func() { os.Remove(socketPath) os.Remove(pidfilePath) @@ -107,6 +122,7 @@ var _ = BeforeSuite(func() { var _ = AfterSuite(func() { os.Remove(socketPath) os.Remove(pidfilePath) + defer os.RemoveAll(tmpDir) }) var _ = Describe("DHCP Operations", func() { @@ -118,6 +134,10 @@ var _ = Describe("DHCP Operations", func() { BeforeEach(func() { dhcpServerStopCh = make(chan bool) + tmpDir, err = getTmpDir() + Expect(err).NotTo(HaveOccurred()) + socketPath = filepath.Join(tmpDir, "dhcp.sock") + // Create a new NetNS so we don't modify the host var err error originalNS, err = testutils.NewNS() @@ -187,7 +207,7 @@ var _ = Describe("DHCP Operations", func() { os.MkdirAll(pidfilePath, 0755) dhcpPluginPath, err := exec.LookPath("dhcp") Expect(err).NotTo(HaveOccurred()) - clientCmd = exec.Command(dhcpPluginPath, "daemon") + clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath) err = clientCmd.Start() Expect(err).NotTo(HaveOccurred()) Expect(clientCmd.Process).NotTo(BeNil()) @@ -212,14 +232,15 @@ var _ = Describe("DHCP Operations", func() { }) It("configures and deconfigures a link with ADD/DEL", func() { - conf := `{ + conf := fmt.Sprintf(`{ "cniVersion": "0.3.1", "name": "mynet", "type": "ipvlan", "ipam": { - "type": "dhcp" + "type": "dhcp", + "daemonSocketPath": "%s" } -}` +}`, socketPath) args := &skel.CmdArgs{ ContainerID: "dummy", @@ -254,14 +275,15 @@ var _ = Describe("DHCP Operations", func() { }) It("correctly handles multiple DELs for the same container", func() { - conf := `{ + conf := fmt.Sprintf(`{ "cniVersion": "0.3.1", "name": "mynet", "type": "ipvlan", "ipam": { - "type": "dhcp" + "type": "dhcp", + "daemonSocketPath": "%s" } -}` +}`, socketPath) args := &skel.CmdArgs{ ContainerID: "dummy", From 3de323f3f0097259c2b5ef48e1850de6d8270ace Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Mon, 8 Oct 2018 11:31:27 -0400 Subject: [PATCH 05/10] Enable ginkgo parallelization in test.sh --- test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.sh b/test.sh index ccc1068b..0c48852d 100755 --- a/test.sh +++ b/test.sh @@ -10,7 +10,7 @@ source ./build.sh echo "Running tests" -GINKGO_FLAGS="-nodes=1 --randomizeAllSpecs --randomizeSuites --failOnPending --progress" +GINKGO_FLAGS="-p --randomizeAllSpecs --randomizeSuites --failOnPending --progress" # user has not provided PKG override if [ -z "$PKG" ]; then From 3d349e464543699401ab055133987d66952f674f Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Mon, 8 Oct 2018 14:08:37 -0400 Subject: [PATCH 06/10] Ensure /run/cni exists in the filesystem before running dhcp tests --- plugins/ipam/dhcp/dhcp_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/ipam/dhcp/dhcp_test.go b/plugins/ipam/dhcp/dhcp_test.go index 2f7d3cec..b929605d 100644 --- a/plugins/ipam/dhcp/dhcp_test.go +++ b/plugins/ipam/dhcp/dhcp_test.go @@ -41,7 +41,7 @@ import ( ) func getTmpDir() (string, error) { - tmpDir, err := ioutil.TempDir("/run/cni", "dhcp") + tmpDir, err := ioutil.TempDir(tmpPrefix, "dhcp") if err == nil { tmpDir = filepath.ToSlash(tmpDir) } @@ -108,6 +108,7 @@ const ( hostVethName string = "dhcp0" contVethName string = "eth0" pidfilePath string = "/var/run/cni/dhcp-client.pid" + tmpPrefix = "/run/cni" ) var socketPath string @@ -117,12 +118,13 @@ var err error var _ = BeforeSuite(func() { os.Remove(socketPath) os.Remove(pidfilePath) + err := os.MkdirAll(tmpPrefix, 0700) + Expect(err).NotTo(HaveOccurred()) }) var _ = AfterSuite(func() { os.Remove(socketPath) os.Remove(pidfilePath) - defer os.RemoveAll(tmpDir) }) var _ = Describe("DHCP Operations", func() { @@ -229,6 +231,7 @@ var _ = Describe("DHCP Operations", func() { Expect(targetNS.Close()).To(Succeed()) os.Remove(socketPath) os.Remove(pidfilePath) + defer os.RemoveAll(tmpDir) }) It("configures and deconfigures a link with ADD/DEL", func() { From ef913eadd58f51b56213f390bac8538080c9cd5e Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Mon, 8 Oct 2018 16:01:31 -0400 Subject: [PATCH 07/10] Took out os.Remove() for socketPath and pidfilePath now that os.RemoveAll() is used --- plugins/ipam/dhcp/dhcp_test.go | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/plugins/ipam/dhcp/dhcp_test.go b/plugins/ipam/dhcp/dhcp_test.go index b929605d..fc2e15b7 100644 --- a/plugins/ipam/dhcp/dhcp_test.go +++ b/plugins/ipam/dhcp/dhcp_test.go @@ -41,7 +41,7 @@ import ( ) func getTmpDir() (string, error) { - tmpDir, err := ioutil.TempDir(tmpPrefix, "dhcp") + tmpDir, err := ioutil.TempDir(cniDirPrefix, "dhcp") if err == nil { tmpDir = filepath.ToSlash(tmpDir) } @@ -108,7 +108,7 @@ const ( hostVethName string = "dhcp0" contVethName string = "eth0" pidfilePath string = "/var/run/cni/dhcp-client.pid" - tmpPrefix = "/run/cni" + cniDirPrefix string = "/var/run/cni" ) var socketPath string @@ -116,17 +116,10 @@ var tmpDir string var err error var _ = BeforeSuite(func() { - os.Remove(socketPath) - os.Remove(pidfilePath) - err := os.MkdirAll(tmpPrefix, 0700) + err := os.MkdirAll(cniDirPrefix, 0700) Expect(err).NotTo(HaveOccurred()) }) -var _ = AfterSuite(func() { - os.Remove(socketPath) - os.Remove(pidfilePath) -}) - var _ = Describe("DHCP Operations", func() { var originalNS, targetNS ns.NetNS var dhcpServerStopCh chan bool @@ -206,7 +199,6 @@ var _ = Describe("DHCP Operations", func() { Expect(err).NotTo(HaveOccurred()) // Start the DHCP client daemon - os.MkdirAll(pidfilePath, 0755) dhcpPluginPath, err := exec.LookPath("dhcp") Expect(err).NotTo(HaveOccurred()) clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath) @@ -229,8 +221,6 @@ var _ = Describe("DHCP Operations", func() { Expect(originalNS.Close()).To(Succeed()) Expect(targetNS.Close()).To(Succeed()) - os.Remove(socketPath) - os.Remove(pidfilePath) defer os.RemoveAll(tmpDir) }) From bf31f089815610714a2ac3867a63864cb671aa7d Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Tue, 9 Oct 2018 16:39:06 -0400 Subject: [PATCH 08/10] Remove unused pidfilePath const --- plugins/ipam/dhcp/dhcp_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/ipam/dhcp/dhcp_test.go b/plugins/ipam/dhcp/dhcp_test.go index fc2e15b7..993e165e 100644 --- a/plugins/ipam/dhcp/dhcp_test.go +++ b/plugins/ipam/dhcp/dhcp_test.go @@ -107,7 +107,6 @@ func dhcpServerStart(netns ns.NetNS, leaseIP, serverIP net.IP, stopCh <-chan boo const ( hostVethName string = "dhcp0" contVethName string = "eth0" - pidfilePath string = "/var/run/cni/dhcp-client.pid" cniDirPrefix string = "/var/run/cni" ) From 73106f0ece9a8b08393b112bbd20ca6d65e72a13 Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Tue, 9 Oct 2018 16:39:06 -0400 Subject: [PATCH 09/10] Remove unused pidfilePath const Moved global var's to BeforeEach() --- plugins/ipam/dhcp/dhcp_test.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/ipam/dhcp/dhcp_test.go b/plugins/ipam/dhcp/dhcp_test.go index fc2e15b7..b865c18f 100644 --- a/plugins/ipam/dhcp/dhcp_test.go +++ b/plugins/ipam/dhcp/dhcp_test.go @@ -107,14 +107,9 @@ func dhcpServerStart(netns ns.NetNS, leaseIP, serverIP net.IP, stopCh <-chan boo const ( hostVethName string = "dhcp0" contVethName string = "eth0" - pidfilePath string = "/var/run/cni/dhcp-client.pid" cniDirPrefix string = "/var/run/cni" ) -var socketPath string -var tmpDir string -var err error - var _ = BeforeSuite(func() { err := os.MkdirAll(cniDirPrefix, 0700) Expect(err).NotTo(HaveOccurred()) @@ -125,6 +120,9 @@ var _ = Describe("DHCP Operations", func() { var dhcpServerStopCh chan bool var dhcpServerDone *sync.WaitGroup var clientCmd *exec.Cmd + var socketPath string + var tmpDir string + var err error BeforeEach(func() { dhcpServerStopCh = make(chan bool) From 22b11bb367aa1c28bb21ea618c6e1c1a1afe146d Mon Sep 17 00:00:00 2001 From: Michael Cambria Date: Wed, 10 Oct 2018 11:35:57 -0400 Subject: [PATCH 10/10] Keep defaultSocketPath the same as before --- plugins/ipam/dhcp/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ipam/dhcp/main.go b/plugins/ipam/dhcp/main.go index b4dbb235..70768b43 100644 --- a/plugins/ipam/dhcp/main.go +++ b/plugins/ipam/dhcp/main.go @@ -29,7 +29,7 @@ import ( "github.com/containernetworking/cni/pkg/version" ) -const defaultSocketPath = "/run/cni/defaultdhcp.sock" +const defaultSocketPath = "/run/cni/dhcp.sock" func main() { if len(os.Args) > 1 && os.Args[1] == "daemon" {