From c7d31ae43a0f94d433e3f51d8d2690d898790697 Mon Sep 17 00:00:00 2001 From: s3rj1k Date: Wed, 6 Sep 2023 17:10:35 +0300 Subject: [PATCH] Honor client bootp flags in response. Signed-off-by: s3rj1k --- README.md | 1 + dhcpv4-reply-raw.go => dhcpv4-reply.go | 26 ++++++++++++++++++++------ dhcpv4-request.go | 3 --- dhcpv4.go | 18 +++++++++++++++--- gpckt/dhcp/utils.go | 15 +++++++++++++++ gpckt/layer.go | 12 ++++++++++++ 6 files changed, 63 insertions(+), 12 deletions(-) rename dhcpv4-reply-raw.go => dhcpv4-reply.go (85%) create mode 100644 gpckt/dhcp/utils.go diff --git a/README.md b/README.md index 392b6c3..ac430b1 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ This repository contains a DHCPv4 Relay agent written in Go (Golang). This relay - [RFC3046: DHCP Relay Agent Information Option](https://www.rfc-editor.org/rfc/rfc3046.html) - [RFC3396: Encoding Long Options in the DHCPv4](https://www.rfc-editor.org/rfc/rfc3396.html) - [RFC3527: Link Selection sub-option for the Relay Agent Information Option for DHCPv4](https://www.rfc-editor.org/rfc/rfc3527.html) +- [RFC5010: Relay Agent Flags Suboption](https://www.rfc-editor.org/rfc/rfc5010.html) - [RFC5107: DHCP Server Identifier Override Suboption](https://www.rfc-editor.org/rfc/rfc5107.html) ### Contribution diff --git a/dhcpv4-reply-raw.go b/dhcpv4-reply.go similarity index 85% rename from dhcpv4-reply-raw.go rename to dhcpv4-reply.go index 43b5961..e0825e9 100644 --- a/dhcpv4-reply-raw.go +++ b/dhcpv4-reply.go @@ -14,10 +14,16 @@ import ( "code.local/dhcp-relay/specs" ) -func HandleDHCPv4GenericReplyRaw( +const ( + UnicastReply uint8 = 0 + BroadcastReply uint8 = 1 +) + +func HandleDHCPv4GenericReply( cfg *HandleOptions, dhcpMessageType string, layerDHCPv4 *layers.DHCPv4, + replyType uint8, ) error { srcIP := layerDHCPv4.RelayAgentIP.To4() if srcIP == nil || srcIP.IsLoopback() || srcIP.Equal(net.IPv4zero) || srcIP.Equal(net.IPv4bcast) { @@ -61,8 +67,6 @@ func HandleDHCPv4GenericReplyRaw( Flags: layers.IPv4DontFragment, TTL: cfg.ReplyTTL, Protocol: layers.IPProtocolUDP, - SrcIP: srcIP.To4(), - DstIP: layerDHCPv4.YourClientIP.To4(), } layerUDP := &layers.UDP{ @@ -84,7 +88,17 @@ func HandleDHCPv4GenericReplyRaw( layerDHCPv4.RelayAgentIP = nil } - dhcp.SetUnicast(layerDHCPv4) + if replyType == UnicastReply { + layerIPv4.SrcIP = srcIP.To4() + layerIPv4.DstIP = layerDHCPv4.YourClientIP.To4() + + dhcp.SetUnicast(layerDHCPv4) + } else if replyType == BroadcastReply { + layerIPv4.SrcIP = net.IPv4zero + layerIPv4.DstIP = net.IPv4bcast + + dhcp.SetBroadcast(layerDHCPv4) + } buffer := gopacket.NewSerializeBuffer() @@ -124,10 +138,10 @@ func HandleDHCPv4GenericReplyRaw( cl.Infof("%s 0x%x: DHCP-%s [%d], IfIndex=%d, Src=%s, Dst=%s\n", logDataOutPrefix, layerDHCPv4.Xid, dhcpMessageType, layerDHCPv4.Len(), ifIndex, net.JoinHostPort( - srcIP.To4().String(), strconv.Itoa(specs.DHCPv4ServerPort), + layerIPv4.SrcIP.String(), strconv.Itoa(specs.DHCPv4ServerPort), ), net.JoinHostPort( - layerDHCPv4.YourClientIP.To4().String(), strconv.Itoa(specs.DHCPv4ClientPort), + layerIPv4.DstIP.String(), strconv.Itoa(specs.DHCPv4ClientPort), ), ) diff --git a/dhcpv4-request.go b/dhcpv4-request.go index 96e8dda..2fe2695 100644 --- a/dhcpv4-request.go +++ b/dhcpv4-request.go @@ -71,7 +71,6 @@ func HandleDHCPv4GenericRequest( dhcp.SetRelayAgentInformationOption(layerDHCPv4, subOpt1) - dhcp.SetUnicast(layerDHCPv4) layerDHCPv4.RelayHops++ for _, addr := range addrs { @@ -106,8 +105,6 @@ func ForwardDHCPv4RelayedRequest( dhcpMessageType string, layerDHCPv4 *layers.DHCPv4, ) error { - dhcp.SetUnicast(layerDHCPv4) - buffer := gopacket.NewSerializeBuffer() err := gopacket.SerializeLayers( diff --git a/dhcpv4.go b/dhcpv4.go index 8d40dc9..65498ac 100644 --- a/dhcpv4.go +++ b/dhcpv4.go @@ -72,9 +72,21 @@ func HandleDHCPv4( funcDataInLog() - if err := HandleDHCPv4GenericReplyRaw(cfg, dhcpMessageType, layerDHCPv4); err != nil { - cl.Errorf("Error handling DHCPv4-%s relayed message: %v\n", - dhcpMessageType, err) + bootFileName := dhcp.GetBootFileName(layerDHCPv4) + if bootFileName != "" { + cl.Debugf("Boot File Name: %s\n", bootFileName) + } + + if dhcp.IsUnicast(layerDHCPv4) { + if err := HandleDHCPv4GenericReply(cfg, dhcpMessageType, layerDHCPv4, UnicastReply); err != nil { + cl.Errorf("Error handling DHCPv4-%s unicast relayed message: %v\n", + dhcpMessageType, err) + } + } else if dhcp.IsBroadcast(layerDHCPv4) { + if err := HandleDHCPv4GenericReply(cfg, dhcpMessageType, layerDHCPv4, BroadcastReply); err != nil { + cl.Errorf("Error handling DHCPv4-%s broadcast relayed message: %v\n", + dhcpMessageType, err) + } } } } diff --git a/gpckt/dhcp/utils.go b/gpckt/dhcp/utils.go new file mode 100644 index 0000000..e4f9c06 --- /dev/null +++ b/gpckt/dhcp/utils.go @@ -0,0 +1,15 @@ +package dhcp + +import ( + "bytes" + + "github.com/gopacket/gopacket/layers" +) + +func GetBootFileName(layerDHCPv4 *layers.DHCPv4) string { + if len(layerDHCPv4.File) == 0 { + return "" + } + + return string(bytes.TrimSpace(layerDHCPv4.File)) +} diff --git a/gpckt/layer.go b/gpckt/layer.go index 9b3fbea..0e54ce0 100644 --- a/gpckt/layer.go +++ b/gpckt/layer.go @@ -1,6 +1,8 @@ package gpckt import ( + "fmt" + "github.com/gopacket/gopacket" "github.com/gopacket/gopacket/layers" ) @@ -60,3 +62,13 @@ func GetDHCPv4(packet gopacket.Packet) *layers.DHCPv4 { return layerDHCPv4 } + +func CopyDHCPv4(layerDHCPv4 *layers.DHCPv4) (*layers.DHCPv4, error) { + out := new(layers.DHCPv4) + + if err := out.DecodeFromBytes(layerDHCPv4.Contents, gopacket.NilDecodeFeedback); err != nil { + return nil, fmt.Errorf("copy error: %w", err) + } + + return out, nil +}