/* * Create DHCP Offer Packet */ func (s *Server) OfferPacket(discoverPacket dhcp4.Packet) dhcp4.Packet { offerPacket := dhcp4.NewPacket(dhcp4.BootReply) offerPacket.SetXId(discoverPacket.XId()) offerPacket.SetFlags(discoverPacket.Flags()) offerPacket.SetCHAddr(discoverPacket.CHAddr()) offerPacket.SetGIAddr(discoverPacket.GIAddr()) offerPacket.SetSecs(discoverPacket.Secs()) //53 offerPacket.AddOption(dhcp4.OptionDHCPMessageType, []byte{byte(dhcp4.Offer)}) //54 offerPacket.AddOption(dhcp4.OptionServerIdentifier, s.ip.To4()) //51 offerPacket.AddOption(dhcp4.OptionIPAddressLeaseTime, dhcp4.OptionsLeaseTime(s.leaseDuration)) //Other options go in requested order... discoverPacketOptions := discoverPacket.ParseOptions() ourOptions := make(dhcp4.Options) //1 ourOptions[dhcp4.OptionSubnetMask] = s.subnetMask.To4() //3 ourOptions[dhcp4.OptionRouter] = s.defaultGateway.To4() //6 ourOptions[dhcp4.OptionDomainNameServer] = dhcp4.JoinIPs(s.dnsServers) if discoverPacketOptions[dhcp4.OptionParameterRequestList] != nil { //Loop through the requested options and if we have them add them. for _, optionCode := range discoverPacketOptions[dhcp4.OptionParameterRequestList] { if !bytes.Equal(ourOptions[dhcp4.OptionCode(optionCode)], []byte{}) { offerPacket.AddOption(dhcp4.OptionCode(optionCode), ourOptions[dhcp4.OptionCode(optionCode)]) delete(ourOptions, dhcp4.OptionCode(optionCode)) } } } //Add all the options not requested. for optionCode, optionValue := range ourOptions { offerPacket.AddOption(optionCode, optionValue) } return offerPacket }
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 }