Example #1
0
/*
 * Lets do a Full DHCP Request.
 */
func (c *Client) Request() (bool, dhcp4.Packet, error) {
	discoveryPacket, err := c.SendDiscoverPacket()
	if err != nil {
		return false, discoveryPacket, err
	}

	offerPacket, err := c.GetOffer(&discoveryPacket)
	if err != nil {
		return false, offerPacket, err
	}

	requestPacket, err := c.SendRequest(&offerPacket)
	if err != nil {
		return false, requestPacket, err
	}

	acknowledgement, err := c.GetAcknowledgement(&requestPacket)
	if err != nil {
		return false, acknowledgement, err
	}

	acknowledgementOptions := acknowledgement.ParseOptions()
	if dhcp4.MessageType(acknowledgementOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.ACK {
		return false, acknowledgement, nil
	}

	return true, acknowledgement, nil
}
Example #2
0
/*
 * 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)
		readBuffer, source, err := c.connection.ReadFrom()
		if err != nil {
			return dhcp4.Packet{}, err
		}

		offerPacket := dhcp4.Packet(readBuffer)
		offerPacketOptions := offerPacket.ParseOptions()

		// Ignore Servers in my Ignore list
		for _, ignoreServer := range c.ignoreServers {
			if source.Equal(ignoreServer) {
				continue
			}

			if offerPacket.SIAddr().Equal(ignoreServer) {
				continue
			}
		}

		if len(offerPacketOptions[dhcp4.OptionDHCPMessageType]) < 1 || dhcp4.MessageType(offerPacketOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.Offer || !bytes.Equal(discoverPacket.XId(), offerPacket.XId()) {
			continue
		}

		return offerPacket, nil
	}

}
Example #3
0
File: client.go Project: vmware/vic
func (c *client) renew(cl *dhcp4client.Client) (dhcp4.Packet, error) {
	defer trace.End(trace.Begin(""))

	rp := cl.RenewalRequestPacket(&c.ack)
	rp, err := c.setOptions(rp)
	if err != nil {
		return nil, err
	}

	rp.PadToMinSize()
	if err = cl.SendPacket(rp); err != nil {
		return nil, err
	}

	newack, err := cl.GetAcknowledgement(&rp)
	if err != nil {
		return nil, err
	}

	opts := newack.ParseOptions()
	if dhcp4.MessageType(opts[dhcp4.OptionDHCPMessageType][0]) == dhcp4.NAK {
		return nil, fmt.Errorf("received NAK from DHCP server")
	}

	return newack, nil
}
Example #4
0
File: client.go Project: vmware/vic
func (c *client) request(cl *dhcp4client.Client) (bool, dhcp4.Packet, error) {
	defer trace.End(trace.Begin(""))

	dp, err := c.discoverPacket(cl)
	if err != nil {
		return false, nil, err
	}

	dp.PadToMinSize()
	if err = cl.SendPacket(dp); err != nil {
		return false, nil, err
	}

	var op dhcp4.Packet
	for {
		op, err = cl.GetOffer(&dp)
		if err != nil {
			return false, nil, err
		}

		if c.isCompletePacket(dhcp.NewPacket([]byte(op))) {
			break
		}
	}

	rp, err := c.requestPacket(cl, &op)
	if err != nil {
		return false, nil, err
	}

	rp.PadToMinSize()
	if err = cl.SendPacket(rp); err != nil {
		return false, nil, err
	}

	ack, err := cl.GetAcknowledgement(&rp)
	if err != nil {
		return false, nil, err
	}

	opts := ack.ParseOptions()
	if dhcp4.MessageType(opts[dhcp4.OptionDHCPMessageType][0]) == dhcp4.NAK {
		return false, nil, fmt.Errorf("Got NAK from DHCP server")
	}

	return true, ack, nil
}
Example #5
0
/*
 * 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()

	err := c.SendPacket(renewRequest)
	if err != nil {
		return false, renewRequest, err
	}

	newAcknowledgement, err := c.GetAcknowledgement(&renewRequest)
	if err != nil {
		return false, newAcknowledgement, err
	}

	newAcknowledgementOptions := newAcknowledgement.ParseOptions()
	if dhcp4.MessageType(newAcknowledgementOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.ACK {
		return false, newAcknowledgement, nil
	}

	return true, newAcknowledgement, nil
}
Example #6
0
func (c *client) renew(id ID, ack dhcp4.Packet, cl *dhcp4client.Client) (dhcp4.Packet, error) {
	rp := cl.RenewalRequestPacket(&ack)
	_, err := c.appendOptions(&rp, id)
	if err != nil {
		return nil, err
	}

	rp.PadToMinSize()
	if err = cl.SendPacket(rp); err != nil {
		return nil, err
	}

	newack, err := cl.GetAcknowledgement(&rp)
	if err != nil {
		return nil, err
	}

	opts := newack.ParseOptions()
	if dhcp4.MessageType(opts[dhcp4.OptionDHCPMessageType][0]) == dhcp4.NAK {
		return nil, fmt.Errorf("received NAK from DHCP server")
	}

	return newack, nil
}
Example #7
0
func (s *Server) ServeDHCP(packet dhcp4.Packet) (dhcp4.Packet, error) {
	packetOptions := packet.ParseOptions()

	switch dhcp4.MessageType(packetOptions[dhcp4.OptionDHCPMessageType][0]) {
	case dhcp4.Discover:

		//Discover Received from client
		//Lets get the lease we're going to send them
		found, lease, err := s.GetLease(packet)
		if err != nil {
			return dhcp4.Packet{}, err
		}

		if !found {
			log.Println("Warning: It Looks Like Our Leases Are Depleted...")
			return dhcp4.Packet{}, nil
		}

		offerPacket := s.OfferPacket(packet)
		offerPacket.SetYIAddr(lease.IP)

		//Sort out the packet options
		offerPacket.PadToMinSize()

		lease.Status = leasepool.Reserved
		lease.MACAddress = packet.CHAddr()

		//If the lease expires within the next 5 Mins increase the lease expiary (Giving the Client 5 mins to complete)
		if lease.Expiry.Before(time.Now().Add(time.Minute * 5)) {
			lease.Expiry = time.Now().Add(time.Minute * 5)
		}

		if packetOptions[dhcp4.OptionHostName] != nil && string(packetOptions[dhcp4.OptionHostName]) != "" {
			lease.Hostname = string(packetOptions[dhcp4.OptionHostName])
		}

		updated, err := s.leasePool.UpdateLease(lease)
		if err != nil {
			return dhcp4.Packet{}, err
		}

		if !updated {
			//Unable to reserve lease (It's now active else where maybe?)
			return dhcp4.Packet{}, errors.New("Unable to Reserve Lease:" + lease.IP.String())
		}

		return offerPacket, nil
	case dhcp4.Request:
		//Request Received from client
		//Lets get the lease we're going to send them
		found, lease, err := s.GetLease(packet)
		if err != nil {
			return dhcp4.Packet{}, err
		}

		if !found {
			log.Println("Warning: It Looks Like Our Leases Are Depleted...")
			return dhcp4.Packet{}, nil
		}

		//If the lease is not the one requested We should send a NAK..
		if len(packetOptions) > 0 && !net.IP(packetOptions[dhcp4.OptionRequestedIPAddress]).Equal(lease.IP) {
			//NAK
			declinePacket := s.DeclinePacket(packet)
			declinePacket.PadToMinSize()

			return declinePacket, nil
		} else {
			lease.Status = leasepool.Active
			lease.MACAddress = packet.CHAddr()

			lease.Expiry = time.Now().Add(s.leaseDuration)

			if packetOptions[dhcp4.OptionHostName] != nil && string(packetOptions[dhcp4.OptionHostName]) != "" {
				lease.Hostname = string(packetOptions[dhcp4.OptionHostName])
			}

			updated, err := s.leasePool.UpdateLease(lease)
			if err != nil {
				return dhcp4.Packet{}, err
			}

			if updated {
				//ACK
				acknowledgementPacket := s.AcknowledgementPacket(packet)
				acknowledgementPacket.SetYIAddr(lease.IP)

				//Lease time.
				acknowledgementPacket.AddOption(dhcp4.OptionIPAddressLeaseTime, dhcp4.OptionsLeaseTime(lease.Expiry.Sub(time.Now())))
				acknowledgementPacket.PadToMinSize()

				return acknowledgementPacket, nil
			} else {
				//NAK
				declinePacket := s.DeclinePacket(packet)
				declinePacket.PadToMinSize()

				return declinePacket, nil
			}
		}
	case dhcp4.Decline:
		//Decline from the client:
		log.Printf("Debug: Decline Message:%v\n", packet)

	case dhcp4.Release:
		//Decline from the client:
		log.Printf("Debug: Release Message:%v\n", packet)

	default:
		log.Printf("Debug: Unexpected Packet Type:%v\n", dhcp4.MessageType(packetOptions[dhcp4.OptionDHCPMessageType][0]))
	}

	return dhcp4.Packet{}, nil
}
Example #8
0
/*
 * 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()
}
Example #9
0
/*
 * 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()
}
Example #10
0
/*
 * 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)
		readBuffer, source, err := c.connection.ReadFrom()
		if err != nil {
			return dhcp4.Packet{}, err
		}

		acknowledgementPacket := dhcp4.Packet(readBuffer)
		acknowledgementPacketOptions := acknowledgementPacket.ParseOptions()

		// Ignore Servers in my Ignore list
		for _, ignoreServer := range c.ignoreServers {
			if source.Equal(ignoreServer) {
				continue
			}

			if acknowledgementPacket.SIAddr().Equal(ignoreServer) {
				continue
			}
		}

		if !bytes.Equal(requestPacket.XId(), acknowledgementPacket.XId()) || len(acknowledgementPacketOptions[dhcp4.OptionDHCPMessageType]) < 1 || (dhcp4.MessageType(acknowledgementPacketOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.ACK && dhcp4.MessageType(acknowledgementPacketOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.NAK) {
			continue
		}

		return acknowledgementPacket, nil
	}
}