157 lines
2.8 KiB
Go
157 lines
2.8 KiB
Go
package dhcp
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
|
|
log "git.wntrmute.dev/kyle/goutils/syslog"
|
|
)
|
|
|
|
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"))
|
|
|
|
for {
|
|
tag, err := buf.ReadByte()
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
return err
|
|
}
|
|
|
|
err = ReadOption(req, tag, buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
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
|
|
}
|