|
|
@ -4,7 +4,6 @@ import (
|
|
|
|
"bytes"
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"encoding/binary"
|
|
|
|
"flag"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/google/gopacket"
|
|
|
|
"github.com/google/gopacket"
|
|
|
|
"github.com/google/gopacket/layers"
|
|
|
|
"github.com/google/gopacket/layers"
|
|
|
|
"github.com/krolaw/dhcp4"
|
|
|
|
"github.com/krolaw/dhcp4"
|
|
|
@ -13,7 +12,8 @@ import (
|
|
|
|
"net"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"os"
|
|
|
|
"proxy/cmd"
|
|
|
|
"proxy/cmd"
|
|
|
|
"proxy/util"
|
|
|
|
. "proxy/util"
|
|
|
|
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
@ -26,6 +26,15 @@ var VmWriter io.Writer
|
|
|
|
var NetReader io.Reader
|
|
|
|
var NetReader io.Reader
|
|
|
|
var NetWriter io.Writer
|
|
|
|
var NetWriter io.Writer
|
|
|
|
var Passthrough bool
|
|
|
|
var Passthrough bool
|
|
|
|
|
|
|
|
var XId []byte
|
|
|
|
|
|
|
|
var DHCPIP net.IP
|
|
|
|
|
|
|
|
var RouterIP net.IP
|
|
|
|
|
|
|
|
var DNSIP net.IP
|
|
|
|
|
|
|
|
var DHCPMAC net.HardwareAddr
|
|
|
|
|
|
|
|
var DHCPMask []byte
|
|
|
|
|
|
|
|
var DHCPState dhcp4.MessageType
|
|
|
|
|
|
|
|
var DHCPCandidate net.IP
|
|
|
|
|
|
|
|
var UId string
|
|
|
|
|
|
|
|
|
|
|
|
// Start the two plugs and run two concurrent forward methods
|
|
|
|
// Start the two plugs and run two concurrent forward methods
|
|
|
|
func main() {
|
|
|
|
func main() {
|
|
|
@ -43,10 +52,11 @@ func main() {
|
|
|
|
flag.Parse()
|
|
|
|
flag.Parse()
|
|
|
|
log.SetLevel(log.Level(*logLvl))
|
|
|
|
log.SetLevel(log.Level(*logLvl))
|
|
|
|
OldMAC, _ = net.ParseMAC(*oldMAC)
|
|
|
|
OldMAC, _ = net.ParseMAC(*oldMAC)
|
|
|
|
NewMAC = util.GenerateMac(*newMAC)
|
|
|
|
NewMAC = GenerateMac(*newMAC)
|
|
|
|
OldIP = net.ParseIP(*oldIP).To4()
|
|
|
|
OldIP = net.ParseIP(*oldIP).To4()
|
|
|
|
NewIP = net.ParseIP(*newIP).To4()
|
|
|
|
NewIP = net.ParseIP(*newIP).To4()
|
|
|
|
Passthrough = *passthrough
|
|
|
|
Passthrough = *passthrough
|
|
|
|
|
|
|
|
UId = GenerateUId(*sockProxy)
|
|
|
|
log.SetFormatter(&log.TextFormatter{
|
|
|
|
log.SetFormatter(&log.TextFormatter{
|
|
|
|
DisableTimestamp: true,
|
|
|
|
DisableTimestamp: true,
|
|
|
|
})
|
|
|
|
})
|
|
|
@ -57,7 +67,7 @@ func main() {
|
|
|
|
log.SetOutput(f)
|
|
|
|
log.SetOutput(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
util.WritePIDFile(*pidFile)
|
|
|
|
WritePIDFile(*pidFile)
|
|
|
|
var c1, c2 *cmd.Cmd
|
|
|
|
var c1, c2 *cmd.Cmd
|
|
|
|
if *sockMain != "-" {
|
|
|
|
if *sockMain != "-" {
|
|
|
|
c1, NetReader, NetWriter = cmd.Start(*sockMain)
|
|
|
|
c1, NetReader, NetWriter = cmd.Start(*sockMain)
|
|
|
@ -68,6 +78,7 @@ func main() {
|
|
|
|
c2, VmReader, VmWriter = cmd.Start(*sockProxy)
|
|
|
|
c2, VmReader, VmWriter = cmd.Start(*sockProxy)
|
|
|
|
go pipeForward(cmd.In)
|
|
|
|
go pipeForward(cmd.In)
|
|
|
|
go pipeForward(cmd.Out)
|
|
|
|
go pipeForward(cmd.Out)
|
|
|
|
|
|
|
|
sendDHCPRequest(dhcp4.Discover, net.IPv4zero)
|
|
|
|
if *sockMain != "-" {
|
|
|
|
if *sockMain != "-" {
|
|
|
|
c1.WaitH()
|
|
|
|
c1.WaitH()
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -103,7 +114,7 @@ func pipeForward(prefix string) {
|
|
|
|
|
|
|
|
|
|
|
|
// Convert frame to full stack packet
|
|
|
|
// Convert frame to full stack packet
|
|
|
|
packet := gopacket.NewPacket(frameBytes, layers.LayerTypeEthernet, gopacket.Default)
|
|
|
|
packet := gopacket.NewPacket(frameBytes, layers.LayerTypeEthernet, gopacket.Default)
|
|
|
|
isInteresting := false // Debug Help
|
|
|
|
// isInteresting := false // Debug Help
|
|
|
|
|
|
|
|
|
|
|
|
// Handle Ethernet frame
|
|
|
|
// Handle Ethernet frame
|
|
|
|
frame := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
|
|
|
frame := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
|
|
@ -117,7 +128,7 @@ func pipeForward(prefix string) {
|
|
|
|
|
|
|
|
|
|
|
|
// Handle DHCPv4 packet (based on IPv4)
|
|
|
|
// Handle DHCPv4 packet (based on IPv4)
|
|
|
|
if dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4); dhcpLayer != nil && !Passthrough {
|
|
|
|
if dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4); dhcpLayer != nil && !Passthrough {
|
|
|
|
handleDHCP(dhcpLayer.LayerContents(), frame.DstMAC, prefix)
|
|
|
|
handleDHCP(dhcpLayer.LayerContents(), frame.DstMAC, frame.SrcMAC, prefix)
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -177,11 +188,11 @@ func pipeForward(prefix string) {
|
|
|
|
binary.BigEndian.PutUint16(newFrameLength, uint16(len(newFrameBytes)))
|
|
|
|
binary.BigEndian.PutUint16(newFrameLength, uint16(len(newFrameBytes)))
|
|
|
|
|
|
|
|
|
|
|
|
// Write interesting things to debug file
|
|
|
|
// Write interesting things to debug file
|
|
|
|
if isInteresting {
|
|
|
|
/*if isInteresting {
|
|
|
|
util.WriteBinary(fmt.Sprintf("/tmp/pck_%di.dat", time.Now().Unix()), frameBytes)
|
|
|
|
WriteBinary(fmt.Sprintf("/tmp/pck_%di.dat", time.Now().Unix()), frameBytes)
|
|
|
|
util.WriteBinary(fmt.Sprintf("/tmp/pck_%do.dat", time.Now().Unix()), newFrameBytes)
|
|
|
|
WriteBinary(fmt.Sprintf("/tmp/pck_%do.dat", time.Now().Unix()), newFrameBytes)
|
|
|
|
//util.WritePcapNg("xyz.pcap", packet.Data(), packet.Metadata().CaptureInfo)
|
|
|
|
//WritePcapNg("xyz.pcap", packet.Data(), packet.Metadata().CaptureInfo)
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
|
|
// Forward modified frame to other plug
|
|
|
|
// Forward modified frame to other plug
|
|
|
|
if _, err := writer.Write(newFrameLength); err != nil {
|
|
|
|
if _, err := writer.Write(newFrameLength); err != nil {
|
|
|
@ -281,7 +292,7 @@ func filterMAC(prefix string, dst interface{}, src interface{}, context gopacket
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func handleDHCP(content []byte, srcMAC net.HardwareAddr, prefix string) {
|
|
|
|
func handleDHCP(content []byte, dstMAC net.HardwareAddr, srcMAC net.HardwareAddr, prefix string) {
|
|
|
|
req := dhcp4.Packet(content)
|
|
|
|
req := dhcp4.Packet(content)
|
|
|
|
if req.HLen() > 16 { // Invalid size
|
|
|
|
if req.HLen() > 16 { // Invalid size
|
|
|
|
log.Error(prefix, "Invalid DHCP size")
|
|
|
|
log.Error(prefix, "Invalid DHCP size")
|
|
|
@ -306,7 +317,9 @@ func handleDHCP(content []byte, srcMAC net.HardwareAddr, prefix string) {
|
|
|
|
if OldIP == nil {
|
|
|
|
if OldIP == nil {
|
|
|
|
log.Fatal(prefix, "DHCPDISCOVER but not previous address is known")
|
|
|
|
log.Fatal(prefix, "DHCPDISCOVER but not previous address is known")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sendDHCPReply(req, dhcp4.Offer, OldIP, options, srcMAC)
|
|
|
|
sendDHCPReply(req, dhcp4.Offer, OldIP, options, dstMAC)
|
|
|
|
|
|
|
|
case dhcp4.Inform:
|
|
|
|
|
|
|
|
fallthrough
|
|
|
|
case dhcp4.Request:
|
|
|
|
case dhcp4.Request:
|
|
|
|
reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
|
|
|
|
reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
|
|
|
|
if reqIP == nil {
|
|
|
|
if reqIP == nil {
|
|
|
@ -316,25 +329,63 @@ func handleDHCP(content []byte, srcMAC net.HardwareAddr, prefix string) {
|
|
|
|
log.Error(prefix, "Invalid IP requested in DHCP: ", reqIP)
|
|
|
|
log.Error(prefix, "Invalid IP requested in DHCP: ", reqIP)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sendDHCPReply(req, dhcp4.ACK, reqIP, options, srcMAC)
|
|
|
|
sendDHCPReply(req, dhcp4.ACK, reqIP, options, dstMAC)
|
|
|
|
default:
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// TODO: talk to DHCP server
|
|
|
|
switch reqType {
|
|
|
|
|
|
|
|
case dhcp4.Offer:
|
|
|
|
|
|
|
|
if DHCPState == dhcp4.Discover {
|
|
|
|
|
|
|
|
DHCPMAC = srcMAC
|
|
|
|
|
|
|
|
offIP := req.YIAddr()
|
|
|
|
|
|
|
|
if len(offIP) != 4 || offIP.Equal(net.IPv4zero) {
|
|
|
|
|
|
|
|
log.Error(prefix, "Invalid IP offered in DHCP: ", offIP)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if dhcpip := options[dhcp4.OptionServerIdentifier]; dhcpip != nil {
|
|
|
|
|
|
|
|
DHCPIP = dhcpip
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if mask := options[dhcp4.OptionSubnetMask]; mask != nil {
|
|
|
|
|
|
|
|
DHCPMask = mask
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if dns := options[dhcp4.OptionDomainNameServer]; dns != nil {
|
|
|
|
|
|
|
|
DNSIP = dns
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if router := options[dhcp4.OptionRouter]; router != nil {
|
|
|
|
|
|
|
|
RouterIP = router
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
DHCPCandidate = offIP
|
|
|
|
|
|
|
|
sendDHCPRequest(dhcp4.Request, offIP)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case dhcp4.ACK:
|
|
|
|
|
|
|
|
if DHCPState == dhcp4.Request {
|
|
|
|
|
|
|
|
NewIP = DHCPCandidate
|
|
|
|
|
|
|
|
DHCPCandidate = nil
|
|
|
|
|
|
|
|
DHCPState = 0
|
|
|
|
|
|
|
|
log.Info("DHCP lease accepted: ", NewIP)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case dhcp4.NAK:
|
|
|
|
|
|
|
|
if DHCPState == dhcp4.Request {
|
|
|
|
|
|
|
|
sendDHCPRequest(dhcp4.Discover, net.IPv4zero)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// sendDHCPReply creates a response DHCP packet and sends it
|
|
|
|
// sendDHCPReply creates a response DHCP packet and sends it
|
|
|
|
func sendDHCPReply(req dhcp4.Packet, mt dhcp4.MessageType, lease net.IP, reqOpt dhcp4.Options, dstMAC net.HardwareAddr) {
|
|
|
|
func sendDHCPReply(req dhcp4.Packet, mt dhcp4.MessageType, lease net.IP, reqOpt dhcp4.Options, dstMAC net.HardwareAddr) {
|
|
|
|
|
|
|
|
if DHCPIP == nil || DHCPMAC == nil {
|
|
|
|
|
|
|
|
log.Info("DHCP server is not known, discover request from VM discarded")
|
|
|
|
|
|
|
|
sendDHCPRequest(dhcp4.Discover, net.IPv4zero)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.Info("Sending DHCP response: ", mt, lease)
|
|
|
|
log.Info("Sending DHCP response: ", mt, lease)
|
|
|
|
|
|
|
|
|
|
|
|
// Getting the options
|
|
|
|
// Getting the options
|
|
|
|
serverIP := []byte{10, 0, 0, 1} // TODO: serverIP
|
|
|
|
|
|
|
|
serverMAC := util.GenerateMac("") // TODO: server MAC
|
|
|
|
|
|
|
|
opt := dhcp4.Options{
|
|
|
|
opt := dhcp4.Options{
|
|
|
|
dhcp4.OptionSubnetMask: []byte{255, 255, 255, 0}, // TODO: subnet mask
|
|
|
|
dhcp4.OptionSubnetMask: DHCPMask,
|
|
|
|
dhcp4.OptionRouter: serverIP, // TODO: Presuming Server is also your router
|
|
|
|
dhcp4.OptionRouter: RouterIP,
|
|
|
|
dhcp4.OptionDomainNameServer: serverIP, // TODO: Presuming Server is also your DNS server
|
|
|
|
dhcp4.OptionDomainNameServer: DNSIP,
|
|
|
|
}.SelectOrderOrAll(reqOpt[dhcp4.OptionParameterRequestList])
|
|
|
|
}.SelectOrderOrAll(reqOpt[dhcp4.OptionParameterRequestList])
|
|
|
|
|
|
|
|
|
|
|
|
// Creating the full packet layer by layer
|
|
|
|
// Creating the full packet layer by layer
|
|
|
@ -344,27 +395,27 @@ func sendDHCPReply(req dhcp4.Packet, mt dhcp4.MessageType, lease net.IP, reqOpt
|
|
|
|
FixLengths: true,
|
|
|
|
FixLengths: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eth := layers.Ethernet{
|
|
|
|
eth := layers.Ethernet{
|
|
|
|
SrcMAC: serverMAC,
|
|
|
|
SrcMAC: DHCPMAC,
|
|
|
|
DstMAC: dstMAC,
|
|
|
|
DstMAC: dstMAC,
|
|
|
|
EthernetType: layers.EthernetTypeIPv4,
|
|
|
|
EthernetType: layers.EthernetTypeIPv4,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ipv4 := layers.IPv4{
|
|
|
|
ipv4 := layers.IPv4{
|
|
|
|
Version: 4,
|
|
|
|
Version: 4,
|
|
|
|
TTL: 64,
|
|
|
|
TTL: 128,
|
|
|
|
Protocol: layers.IPProtocolUDP,
|
|
|
|
Protocol: layers.IPProtocolUDP,
|
|
|
|
SrcIP: serverIP,
|
|
|
|
SrcIP: DHCPIP,
|
|
|
|
DstIP: lease,
|
|
|
|
DstIP: lease,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
udp := layers.UDP{
|
|
|
|
udp := layers.UDP{
|
|
|
|
SrcPort: 67,
|
|
|
|
SrcPort: 67,
|
|
|
|
DstPort: 68,
|
|
|
|
DstPort: 68,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dhcp := dhcp4.ReplyPacket(req, mt, serverIP, lease, 24*time.Hour, opt)
|
|
|
|
dhcp := dhcp4.ReplyPacket(req, mt, DHCPIP, lease, 24*time.Hour, opt)
|
|
|
|
if err := udp.SetNetworkLayerForChecksum(&ipv4); err != nil {
|
|
|
|
if err := udp.SetNetworkLayerForChecksum(&ipv4); err != nil {
|
|
|
|
log.Error("Error building DHCP response", err)
|
|
|
|
log.Error("Error building DHCP response:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := gopacket.SerializeLayers(buf, opts, ð, &ipv4, &udp, gopacket.Payload(dhcp)); err != nil {
|
|
|
|
if err := gopacket.SerializeLayers(buf, opts, ð, &ipv4, &udp, gopacket.Payload(dhcp)); err != nil {
|
|
|
|
log.Error("Error serializing DHCP response", err)
|
|
|
|
log.Error("Error serializing DHCP response:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
packetData := buf.Bytes()
|
|
|
|
packetData := buf.Bytes()
|
|
|
|
|
|
|
|
|
|
|
@ -379,3 +430,69 @@ func sendDHCPReply(req dhcp4.Packet, mt dhcp4.MessageType, lease net.IP, reqOpt
|
|
|
|
log.Error("Error writing DHCP response data", err)
|
|
|
|
log.Error("Error writing DHCP response data", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func sendDHCPRequest(mt dhcp4.MessageType, reqIP net.IP) {
|
|
|
|
|
|
|
|
log.Info("Sending DHCP request: ", mt)
|
|
|
|
|
|
|
|
if mt == dhcp4.Discover {
|
|
|
|
|
|
|
|
XId = GenerateXID()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
DHCPState = mt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Creating the full packet layer by layer
|
|
|
|
|
|
|
|
buf := gopacket.NewSerializeBuffer()
|
|
|
|
|
|
|
|
serializeOpts := gopacket.SerializeOptions{
|
|
|
|
|
|
|
|
ComputeChecksums: true,
|
|
|
|
|
|
|
|
FixLengths: true,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
eth := layers.Ethernet{
|
|
|
|
|
|
|
|
SrcMAC: NewMAC,
|
|
|
|
|
|
|
|
DstMAC: If(mt == dhcp4.Discover).MAC([]byte{255,255,255,255,255,255}, DHCPMAC),
|
|
|
|
|
|
|
|
EthernetType: layers.EthernetTypeIPv4,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ipv4 := layers.IPv4{
|
|
|
|
|
|
|
|
Version: 4,
|
|
|
|
|
|
|
|
TTL: 128,
|
|
|
|
|
|
|
|
Protocol: layers.IPProtocolUDP,
|
|
|
|
|
|
|
|
SrcIP: net.IPv4zero,
|
|
|
|
|
|
|
|
DstIP: net.IPv4bcast,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
udp := layers.UDP{
|
|
|
|
|
|
|
|
SrcPort: 68,
|
|
|
|
|
|
|
|
DstPort: 67,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dhcpOpts := []dhcp4.Option{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Code: dhcp4.OptionHostName,
|
|
|
|
|
|
|
|
Value: []byte("vdeproxy" + UId),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Code: dhcp4.OptionParameterRequestList,
|
|
|
|
|
|
|
|
Value: []byte{1, 3, 6}, // Subnet Mask, Router, Domain Name Server
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if mt == dhcp4.Request {
|
|
|
|
|
|
|
|
dhcpOpts = append(dhcpOpts, dhcp4.Option{
|
|
|
|
|
|
|
|
Code: dhcp4.OptionRequestedIPAddress,
|
|
|
|
|
|
|
|
Value: reqIP.To4(),
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dhcp := dhcp4.RequestPacket(mt, NewMAC, reqIP, XId, false, dhcpOpts)
|
|
|
|
|
|
|
|
if err := udp.SetNetworkLayerForChecksum(&ipv4); err != nil {
|
|
|
|
|
|
|
|
log.Error("Error building DHCP request: ", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := gopacket.SerializeLayers(buf, serializeOpts, ð, &ipv4, &udp, gopacket.Payload(dhcp)); err != nil {
|
|
|
|
|
|
|
|
log.Error("Error serializing DHCP request: ", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
packetData := buf.Bytes()
|
|
|
|
|
|
|
|
WritePcap("/tmp/dhcpreq_" +strconv.FormatInt(time.Now().Unix(), 10)+ ".pcap", packetData)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sending layer through VM's pipe
|
|
|
|
|
|
|
|
packetLength := make([]byte, 2)
|
|
|
|
|
|
|
|
binary.BigEndian.PutUint16(packetLength, uint16(len(packetData)))
|
|
|
|
|
|
|
|
if _, err := NetWriter.Write(packetLength); err != nil {
|
|
|
|
|
|
|
|
log.Error("Error writing DHCP response length: ", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := NetWriter.Write(packetData); err != nil {
|
|
|
|
|
|
|
|
log.Error("Error writing DHCP response data: ", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|