// YourIP returns the YIP field in the packet (this is IP assigned by server to the client) func (p *Packet) YourIP() net.IP { if len(p.Packet) == 0 { return nil } return dhcp4.Packet(p.Packet).YIAddr() }
/* * 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 } }
/* * 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 } }
func (c *client) Renew(id ID, ack *dhcp.Packet) (*dhcp.Packet, error) { c.Lock() defer c.Unlock() log.Debugf("renewing IP %s", ack.YourIP()) cl, err := c.newClient(ack) if err != nil { return nil, err } defer cl.Close() p := dhcp4.Packet(ack.Packet) var newack dhcp4.Packet err = withRetry(func() error { var err error newack, err = c.renew(id, p, cl) return err }) if err != nil { return nil, err } return dhcp.NewPacket([]byte(newack)), nil }
func (c *client) Release(ack *dhcp.Packet) error { c.Lock() defer c.Unlock() log.Debugf("releasing IP %s", ack.YourIP()) cl, err := c.newClient(ack) if err != nil { return err } defer cl.Close() return withRetry(func() error { return cl.Release(dhcp4.Packet(ack.Packet)) }) }
/* * Start The DHCP Server */ func (s *Server) ListenAndServe() error { var err error connection, err := net.ListenPacket("udp4", s.laddr.String()) if err != nil { log.Printf("Debug: Error Returned From ListenPacket On \"%s\" Because of \"%s\"\n", s.laddr.String(), err.Error()) return err } s.connection = ipv4.NewPacketConn(connection) defer s.connection.Close() //We Currently Don't Use this Feature Which is the only bit that is Linux Only. //if err := s.connection.SetControlMessage(ipv4.FlagInterface, true); err != nil { // return err //} //Make Our Buffer (Max Buffer is 574) "I believe this 576 size comes from RFC 791" - Random Mailing list quote of the day. buffer := make([]byte, 576) log.Println("Trace: DHCP Server Listening.") for { ListenForDHCPPackets: if s.shutdown { return nil } //Set Read Deadline s.connection.SetReadDeadline(time.Now().Add(time.Second)) // Read Packet n, control_message, source, err := s.connection.ReadFrom(buffer) if err != nil { switch v := err.(type) { case *net.OpError: if v.Timeout() { goto ListenForDHCPPackets } case *net.AddrError: if v.Timeout() { goto ListenForDHCPPackets } case *net.UnknownNetworkError: if v.Timeout() { goto ListenForDHCPPackets } } log.Println("Debug: Unexpect Error from Connection Read From:" + err.Error()) return err } //We seem to have an issue with undersized packets? if n < 240 { log.Printf("Error: Invalid Packet Size \"%d\" Received:%v\n", n, buffer[:n]) continue } //We should ignore some requests //It shouldn't be possible to ignore IP's because they shouldn't have them as we're the DHCP server. //However, they can have i.e. if you're the client & server :S. for _, ipToIgnore := range s.ignoreIPs { if ipToIgnore.Equal(source.(*net.UDPAddr).IP) { log.Println("Debug: Ignoring DHCP Request From IP:" + ipToIgnore.String()) continue } } packet := dhcp4.Packet(buffer[:n]) //We can ignore hardware addresses. //Usefull for ignoring a range of hardware addresses for _, hardwareAddressToIgnore := range s.ignoreHardwareAddress { if bytes.Equal(hardwareAddressToIgnore, packet.CHAddr()) { log.Println("Debug: Ignoring DHCP Request From Hardware Address:" + hardwareAddressToIgnore.String()) continue } } log.Printf("Trace: Packet Received ID:%v\n", packet.XId()) log.Printf("Trace: Packet Options:%v\n", packet.ParseOptions()) log.Printf("Trace: Packet Client IP : %v\n", packet.CIAddr().String()) log.Printf("Trace: Packet Your IP : %v\n", packet.YIAddr().String()) log.Printf("Trace: Packet Server IP : %v\n", packet.SIAddr().String()) log.Printf("Trace: Packet Gateway IP: %v\n", packet.GIAddr().String()) log.Printf("Trace: Packet Client Mac: %v\n", packet.CHAddr().String()) //We need to stop butting in with other servers. if packet.SIAddr().Equal(net.IPv4(0, 0, 0, 0)) || packet.SIAddr().Equal(net.IP{}) || packet.SIAddr().Equal(s.ip) { returnPacket, err := s.ServeDHCP(packet) if err != nil { log.Println("Debug: Error Serving DHCP:" + err.Error()) return err } if len(returnPacket) > 0 { log.Printf("Trace: Packet Returned ID:%v\n", returnPacket.XId()) log.Printf("Trace: Packet Options:%v\n", returnPacket.ParseOptions()) log.Printf("Trace: Packet Client IP : %v\n", returnPacket.CIAddr().String()) log.Printf("Trace: Packet Your IP : %v\n", returnPacket.YIAddr().String()) log.Printf("Trace: Packet Server IP : %v\n", returnPacket.SIAddr().String()) log.Printf("Trace: Packet Gateway IP: %v\n", returnPacket.GIAddr().String()) log.Printf("Trace: Packet Client Mac: %v\n", returnPacket.CHAddr().String()) _, err = s.connection.WriteTo(returnPacket, control_message, &s.raddr) if err != nil { log.Println("Debug: Error Writing:" + err.Error()) return err } } } } }
func NewPacket(p []byte) *Packet { return &Packet{Packet: p, Options: Options(dhcp4.Packet(p).ParseOptions())} }