package dhcp import ( "bytes" "encoding/binary" "fmt" "net" "strings" "git.wntrmute.dev/kyle/kdhcp/log" "github.com/davecgh/go-spew/spew" ) const ( maxHardwareAddrLen = 16 maxServerName = 64 maxFileName = 128 ) var anyAddr = net.IP([]byte{0, 0, 0, 0}) func formatMAC(mac []byte) string { s := []string{} for i := 0; i < len(mac); i++ { s = append(s, fmt.Sprintf("%0x", mac[i:i+1])) } return strings.Join(s, ":") } type BootRequest struct { MessageType uint8 HardwareType uint8 HardwareAddress []byte Hops uint8 TransactionID uint32 SecondsElapsed uint16 Flags uint16 ServerName string FileName string ClientIP net.IP YourIP net.IP NextIP net.IP RelayIP net.IP DHCPType uint8 // option 53 HostName string // option 12 ParameterRequests []string } func (req *BootRequest) Read(packet []byte) error { buf := bytes.NewBuffer(packet) read := func(v any) error { return binary.Read(buf, binary.BigEndian, v) } if err := read(&req.MessageType); err != nil { return err } if err := read(&req.HardwareType); err != nil { return err } var hwaLength uint8 if err := read(&hwaLength); err != nil { return err } if err := read(&req.Hops); err != nil { return err } if err := read(&req.TransactionID); err != nil { return err } if err := read(&req.SecondsElapsed); err != nil { return err } if err := read(&req.Flags); err != nil { return err } req.ClientIP = anyAddr[:] if _, err := buf.Read(req.ClientIP); err != nil { return err } req.YourIP = anyAddr[:] if _, err := buf.Read(req.YourIP); err != nil { return err } req.NextIP = anyAddr[:] if _, err := buf.Read(req.NextIP); err != nil { return err } req.RelayIP = anyAddr[:] if _, err := buf.Read(req.RelayIP); err != nil { return err } req.HardwareAddress = make([]byte, int(hwaLength)) if _, err := buf.Read(req.HardwareAddress); err != nil { return err } hwaPad := make([]byte, maxHardwareAddrLen-hwaLength) if _, err := buf.Read(hwaPad); err != nil { return err } log.Debugf("padding: %x", hwaPad) tempBuf := make([]byte, maxServerName) if _, err := buf.Read(tempBuf); err != nil { return err } req.ServerName = string(bytes.Trim(tempBuf, "\x00")) tempBuf = make([]byte, maxFileName) if _, err := buf.Read(tempBuf); err != nil { return err } req.FileName = string(bytes.Trim(tempBuf, "\x00")) spew.Dump(*req) return nil } func ReadRequest(pkt []byte) (*BootRequest, error) { req := &BootRequest{} err := req.Read(pkt) if err != nil { return nil, err } log.Debugf("dhcp: BOOTP request with txid %d for %s", req.TransactionID, formatMAC(req.HardwareAddress)) return req, nil }