Starting DHCP packets.

This commit is contained in:
2023-05-02 23:33:14 +00:00
parent 3ec9af1fde
commit ac41c7a480
17 changed files with 11743 additions and 32 deletions

15
dhcp/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "dhcp",
srcs = [
"options.go",
"packet.go",
],
importpath = "git.wntrmute.dev/kyle/kdhcp/dhcp",
visibility = ["//visibility:public"],
deps = [
"//log",
"@com_github_davecgh_go_spew//spew",
],
)

46
dhcp/options.go Normal file
View File

@@ -0,0 +1,46 @@
package dhcp
import (
"errors"
"io"
)
type OptionTag uint8
type Option func(req *BootRequest, r io.Reader) error
const (
OptionTagPadding OptionTag = 0
OptionTagHostName = 12
OptionTagMessageType = 53
OptionTagParameterRequestList = 55
OptionTagEnd = 255
)
var optionRegistry = map[OptionTag]Option{
OptionTagPadding: OptionTag,
OptionTagHostName: OptionHostName,
OptionTagMessageType: OptionMessageType,
OptionTagParameterRequestList: OptionParameterRequestList,
OptionTagEnd: OptionEnd,
}
func OptionPad(req *BootRequest, r io.Reader) error {
return nil
}
func OptionHostName(req *BootRequest, r io.Reader) error {
return errors.New("dhcp: option not implemented yet")
}
func OptionMessageType(req *BootRequest, r io.Reader) error {
return errors.New("dhcp: option not implemented yet")
}
func OptionParameterRequestList(req *BootRequest, r io.Reader) error {
return errors.New("dhcp: option not implemented yet")
}
func OptionEnd(req *BootRequest, r io.Reader) error {
return errors.New("dhcp: option not implemented yet")
}

143
dhcp/packet.go Normal file
View File

@@ -0,0 +1,143 @@
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
}