Du kannst nicht mehr als 25 Themen auswählen
Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
565 Zeilen
16 KiB
Go
565 Zeilen
16 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"flag"
|
|
"github.com/google/gopacket"
|
|
"github.com/google/gopacket/layers"
|
|
"github.com/krolaw/dhcp4"
|
|
log "github.com/sirupsen/logrus"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"proxy/cmd"
|
|
. "proxy/util"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
var OldMAC net.HardwareAddr
|
|
var NewMAC net.HardwareAddr
|
|
var OldIP net.IP
|
|
var NewIP net.IP
|
|
|
|
// In-/Output to VM and network
|
|
|
|
var VmReader io.Reader
|
|
var VmWriter io.Writer
|
|
var NetReader io.Reader
|
|
var NetWriter io.Writer
|
|
|
|
// DHCP variables
|
|
|
|
var DHCPXId []byte
|
|
var DHCPIP net.IP
|
|
var DHCPRouterIP net.IP
|
|
var DHCPDNSIP net.IP
|
|
var DHCPMAC net.HardwareAddr
|
|
var DHCPMask []byte
|
|
var DHCPState dhcp4.MessageType
|
|
var DHCPCandidate net.IP
|
|
|
|
// User-provided variables
|
|
|
|
var Hostname string
|
|
var Passthrough bool
|
|
var Wireshark bool
|
|
|
|
// UId used as host name
|
|
var UId string
|
|
|
|
// Start the two plugs and run two concurrent forward methods
|
|
func main() {
|
|
// Get command line arguments
|
|
logLvl := flag.Int("log", 4, "allowed: 5 (debug), 4 (info), 3 (warning), 2 (error), 1 (fatal)")
|
|
oldIP := flag.String("oldip", "", "Force IP before change (optional)")
|
|
newIP := flag.String("newip", "", "Force IP after change (optional)")
|
|
oldMAC := flag.String("oldmac", "", "Force MAC before change (optional)")
|
|
newMAC := flag.String("newmac", "", "Force MAC after change (optional)")
|
|
passthrough := flag.Bool("passthrough", false, "Whether to pass every traffic through")
|
|
sockMain := flag.String("smain", "/run/vde/sw_main.sock", "Main switch sock path, - for stdin/out")
|
|
sockProxy := flag.String("sproxy", "/run/vde/sw_proxy1.sock", "Proxy switch sock path")
|
|
pidFile := flag.String("pidfile", "", "Location to write the pid to (optional)")
|
|
logFile := flag.String("logfile", "", "Location to write output to (optional)")
|
|
wireshark := flag.Bool("wireshark", false, "Whether to write all traffic to /tmp")
|
|
hostname := flag.String("hostname", "", "Set a windows hostname to filter for in binary payloads")
|
|
flag.Parse()
|
|
log.SetLevel(log.Level(*logLvl))
|
|
OldMAC, _ = net.ParseMAC(*oldMAC)
|
|
NewMAC = GenerateMac(*newMAC)
|
|
OldIP = net.ParseIP(*oldIP).To4()
|
|
NewIP = net.ParseIP(*newIP).To4()
|
|
Passthrough = *passthrough
|
|
Wireshark = *wireshark
|
|
Hostname = *hostname
|
|
UId = GenerateUId(*sockProxy)
|
|
log.SetFormatter(&log.TextFormatter{
|
|
DisableTimestamp: true,
|
|
})
|
|
if *logFile != "" {
|
|
if f, err := os.OpenFile(*logFile, os.O_WRONLY|os.O_CREATE, 0755); err != nil {
|
|
log.Error("Error opening logFile ", *logFile)
|
|
} else {
|
|
log.SetOutput(f)
|
|
}
|
|
}
|
|
WritePIDFile(*pidFile)
|
|
var c1, c2 *cmd.Cmd
|
|
if *sockMain != "-" {
|
|
c1, NetReader, NetWriter = cmd.Start(*sockMain)
|
|
} else {
|
|
NetReader = os.Stdout
|
|
NetWriter = os.Stdin
|
|
}
|
|
c2, VmReader, VmWriter = cmd.Start(*sockProxy)
|
|
go pipeForward(In)
|
|
go pipeForward(Out)
|
|
if NewIP == nil && !Passthrough {
|
|
sendDHCPRequest(dhcp4.Discover, net.IPv4zero)
|
|
}
|
|
if *sockMain != "-" {
|
|
c1.WaitH()
|
|
}
|
|
c2.WaitH()
|
|
}
|
|
|
|
// Reads from an input and writes to and output,
|
|
// do things to the content in between.
|
|
// Is meant to be run concurrently with "go pipeForward(...)".
|
|
// This is the main loop of the proxy.
|
|
func pipeForward(prefix string) {
|
|
var reader io.Reader
|
|
var writer io.Writer
|
|
if prefix == In {
|
|
reader = NetReader
|
|
writer = VmWriter
|
|
} else {
|
|
reader = VmReader
|
|
writer = NetWriter
|
|
}
|
|
|
|
for {
|
|
// Read frame length
|
|
frameLength := make([]byte, 2)
|
|
if _, err := reader.Read(frameLength); err == io.EOF {
|
|
log.Fatal(prefix, "Error reading frame length")
|
|
}
|
|
|
|
// Read actual frame
|
|
frameBytes := make([]byte, int(binary.BigEndian.Uint16(frameLength)))
|
|
if _, err := reader.Read(frameBytes); err == io.EOF {
|
|
log.Fatal(prefix, "Error reading frame data")
|
|
}
|
|
|
|
if Wireshark {
|
|
WritePcap("/tmp/pkg_"+strconv.FormatInt(time.Now().Unix(), 10)+".pcap", frameBytes)
|
|
}
|
|
|
|
// Forward original frame to other plug
|
|
if Passthrough {
|
|
if _, err := writer.Write(frameLength); err != nil {
|
|
log.Error("Error forwarding original packet length", err)
|
|
}
|
|
if _, err := writer.Write(frameBytes); err != nil {
|
|
log.Error("Error forwarding original packet data", err)
|
|
}
|
|
continue
|
|
}
|
|
|
|
// Convert frame to full stack packet
|
|
packet := gopacket.NewPacket(frameBytes, layers.LayerTypeEthernet, gopacket.Default)
|
|
|
|
// Handle Ethernet frame
|
|
log.Debug("Start packet")
|
|
frame := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
|
filterMAC(prefix, &frame.DstMAC, &frame.SrcMAC, frame.LayerType())
|
|
|
|
// Handle IPv4 packet
|
|
if ipv4layer := packet.Layer(layers.LayerTypeIPv4); ipv4layer != nil {
|
|
ipv4Packet, _ := ipv4layer.(*layers.IPv4)
|
|
log.Debug("IP Protocol ", ipv4Packet.Protocol)
|
|
|
|
// Handle DHCPv4 packet (based on IPv4)
|
|
if dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4); dhcpLayer != nil {
|
|
handleDHCP(dhcpLayer.LayerContents(), frame.DstMAC, frame.SrcMAC, prefix)
|
|
continue
|
|
}
|
|
|
|
filterIP(prefix, &ipv4Packet.DstIP, &ipv4Packet.SrcIP, ipv4Packet.LayerType())
|
|
|
|
// Handle ICMP packet (based on IPv4)
|
|
if icmpLayer := packet.Layer(layers.LayerTypeICMPv4); icmpLayer != nil {
|
|
icmpPacket, _ := icmpLayer.(*layers.ICMPv4)
|
|
log.Debug(prefix, "ICMP Type ", icmpPacket.TypeCode)
|
|
}
|
|
|
|
// Handle TCP packet
|
|
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
|
|
tcpPacket, _ := tcpLayer.(*layers.TCP)
|
|
if err := tcpPacket.SetNetworkLayerForChecksum(ipv4Packet); err != nil {
|
|
log.Error(prefix, "Error setting network layer for TCP checksum", err)
|
|
}
|
|
}
|
|
|
|
// Handle UDP packet
|
|
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
|
|
udpPacket, _ := udpLayer.(*layers.UDP)
|
|
if err := udpPacket.SetNetworkLayerForChecksum(ipv4Packet); err != nil {
|
|
log.Error(prefix, "Error setting network layer for UDP checksum", err)
|
|
}
|
|
|
|
if (udpPacket.SrcPort == 137 && udpPacket.DstPort == 137) || // NBNS
|
|
(udpPacket.SrcPort == 138 && udpPacket.DstPort == 138) { // NBDS
|
|
log.Info(prefix, "Filtering NBNS/NBDS payload")
|
|
filterPayload(prefix, &udpPacket.Payload)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Drop IPv6 packets
|
|
if ipv6layer := packet.Layer(layers.LayerTypeIPv6); ipv6layer != nil {
|
|
log.Info(prefix, "IPv6 packet dropped")
|
|
continue
|
|
}
|
|
|
|
// Handle ARP packet
|
|
if frame.EthernetType == layers.EthernetTypeARP {
|
|
arpPacket := packet.Layer(layers.LayerTypeARP).(*layers.ARP)
|
|
log.Debug(prefix, "ARP Type ", arpPacket.Operation)
|
|
filterIP(prefix, &arpPacket.DstProtAddress, &arpPacket.SourceProtAddress, arpPacket.LayerType())
|
|
filterMAC(prefix, &arpPacket.DstHwAddress, &arpPacket.SourceHwAddress, arpPacket.LayerType())
|
|
}
|
|
|
|
log.Debug("End packet")
|
|
|
|
// Serialize packet back to binary
|
|
buf := gopacket.NewSerializeBuffer()
|
|
opts := gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
|
|
if err := gopacket.SerializePacket(buf, opts, packet); err != nil {
|
|
log.Errorf("%s Error serializing packet to send\n%s\nSrc:\t%s\nDst:\t%s\n", prefix, err, frame.SrcMAC, frame.DstMAC)
|
|
continue
|
|
}
|
|
newFrameBytes := buf.Bytes()
|
|
newFrameLength := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(newFrameLength, uint16(len(newFrameBytes)))
|
|
|
|
// Forward modified frame to other plug
|
|
if _, err := writer.Write(newFrameLength); err != nil {
|
|
log.Error("Error forwarding packet length", err)
|
|
}
|
|
if _, err := writer.Write(newFrameBytes); err != nil {
|
|
log.Error("Error forwarding packet data", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// filterPayloads filters binary payloads to be able to process unsupported protocols
|
|
func filterPayload(prefix string, payload *[]byte) {
|
|
// Populate slices with values to on vm and network side
|
|
vmVals := [][]byte{OldMAC}
|
|
netVals := [][]byte{NewMAC}
|
|
if OldIP != nil && !OldIP.Equal(NewIP) {
|
|
vmVals = append(vmVals, OldIP)
|
|
netVals = append(netVals, NewIP)
|
|
}
|
|
if Hostname != "" {
|
|
vmVals = append(vmVals, []byte(Hostname), DnsQueryEncode(Hostname))
|
|
netVals = append(netVals, []byte(UId), DnsQueryEncode(UId))
|
|
}
|
|
|
|
// Choose for which slice to search for and which to replace it with
|
|
searchVals := vmVals
|
|
replaceVals := netVals
|
|
if prefix == In {
|
|
searchVals = netVals
|
|
replaceVals = vmVals
|
|
}
|
|
|
|
// Replace all occurencies of each slice value
|
|
for i, search := range searchVals {
|
|
*payload = bytes.Replace(*payload, search, replaceVals[i], -1)
|
|
}
|
|
}
|
|
|
|
// filterIP checks whether an IP target selected from src and dst equals a given value. If yes, it is changed
|
|
func filterIP(prefix string, dst interface{}, src interface{}, context gopacket.LayerType) {
|
|
var target interface{}
|
|
var condVal net.IP
|
|
var newVal net.IP
|
|
var which string
|
|
if prefix == In {
|
|
target = dst
|
|
which = "dst"
|
|
condVal = NewIP
|
|
newVal = OldIP
|
|
} else if prefix == Out {
|
|
target = src
|
|
which = "src"
|
|
condVal = OldIP
|
|
newVal = NewIP
|
|
}
|
|
ip, isIp := target.(*net.IP)
|
|
bs, isBs := target.(*[]byte)
|
|
|
|
// If no OldIP is set yet, get it from outgoing src field
|
|
if OldIP == nil {
|
|
if prefix == In {
|
|
return
|
|
} else if prefix == Out {
|
|
if isIp {
|
|
if !ip.IsGlobalUnicast() {
|
|
return
|
|
}
|
|
OldIP = *ip
|
|
} else if isBs {
|
|
OldIP = *bs
|
|
}
|
|
log.Info("OldIP set to ", OldIP)
|
|
condVal = OldIP
|
|
}
|
|
}
|
|
|
|
if isIp && bytes.Equal(*ip, condVal) {
|
|
*ip = newVal
|
|
log.Debugf("%s%s %s IP %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
if isBs && bytes.Equal(*bs, condVal) {
|
|
*bs = newVal
|
|
log.Debugf("%s%s %s IP %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
}
|
|
|
|
// filterMAC checks whether a MAC target selected from src and dst equals a given value. If yes, it is changed
|
|
func filterMAC(prefix string, dst interface{}, src interface{}, context gopacket.LayerType) {
|
|
// If no OldMAC is set yet, get it from outgoing src field
|
|
// Has to be HardwareAddr because this is used for ethernet frames which call this method first
|
|
if OldMAC == nil {
|
|
if prefix == In {
|
|
return
|
|
} else if prefix == Out {
|
|
OldMAC = *src.(*net.HardwareAddr)
|
|
log.Info("OldMAC set to ", OldMAC)
|
|
}
|
|
}
|
|
|
|
var target interface{}
|
|
var condVal net.HardwareAddr
|
|
var newVal net.HardwareAddr
|
|
var which string
|
|
if prefix == In {
|
|
target = dst
|
|
which = "dst"
|
|
condVal = NewMAC
|
|
newVal = OldMAC
|
|
} else if prefix == Out {
|
|
target = src
|
|
which = "src"
|
|
condVal = OldMAC
|
|
newVal = NewMAC
|
|
}
|
|
mac, isMac := target.(*net.HardwareAddr)
|
|
bs, isBs := target.(*[]byte)
|
|
if isMac && bytes.Equal(*mac, condVal) {
|
|
*mac = newVal
|
|
log.Debugf("%s%s %s MAC %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
if isBs && bytes.Equal(*bs, condVal) {
|
|
*bs = newVal
|
|
log.Debugf("%s%s %s MAC %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
}
|
|
|
|
// handleDHCP provides the main DHCP functionality to request an IP from a server on the one hand
|
|
// and provide an IP to the VM on the other hand
|
|
func handleDHCP(content []byte, dstMAC net.HardwareAddr, srcMAC net.HardwareAddr, prefix string) {
|
|
req := dhcp4.Packet(content)
|
|
if req.HLen() > 16 { // Invalid size
|
|
log.Error(prefix, "Invalid DHCP size")
|
|
return
|
|
}
|
|
options := req.ParseOptions()
|
|
var reqType dhcp4.MessageType
|
|
if t := options[dhcp4.OptionDHCPMessageType]; len(t) != 1 {
|
|
log.Error(prefix, "Invalid DHCP message type")
|
|
return
|
|
} else {
|
|
reqType = dhcp4.MessageType(t[0])
|
|
if reqType < dhcp4.Discover || reqType > dhcp4.Inform {
|
|
log.Error(prefix, "Invalid DHCP message type: ", reqType)
|
|
return
|
|
}
|
|
}
|
|
log.Debug(prefix, "DHCP message registered: ", reqType)
|
|
if prefix == Out {
|
|
switch reqType {
|
|
case dhcp4.Discover:
|
|
if OldIP == nil {
|
|
if NewIP == nil || !NewIP.IsGlobalUnicast() {
|
|
log.Warning(prefix, "DHCP request, but neither OldIP nor NewIP known")
|
|
sendDHCPRequest(dhcp4.Discover, net.IPv4zero)
|
|
return
|
|
}
|
|
sendDHCPReply(req, dhcp4.Offer, NewIP, options, dstMAC)
|
|
} else {
|
|
sendDHCPReply(req, dhcp4.Offer, OldIP, options, dstMAC)
|
|
}
|
|
case dhcp4.Inform:
|
|
fallthrough
|
|
case dhcp4.Request:
|
|
reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
|
|
if reqIP == nil {
|
|
reqIP = req.CIAddr()
|
|
}
|
|
if len(reqIP) != 4 || reqIP.Equal(net.IPv4zero) {
|
|
log.Error(prefix, "Invalid IP requested in DHCP: ", reqIP)
|
|
return
|
|
}
|
|
sendDHCPReply(req, dhcp4.ACK, reqIP, options, dstMAC)
|
|
}
|
|
} else {
|
|
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 {
|
|
DHCPDNSIP = dns
|
|
}
|
|
if router := options[dhcp4.OptionRouter]; router != nil {
|
|
DHCPRouterIP = 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 for the VM and sends it
|
|
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)
|
|
|
|
// Getting the options
|
|
opt := dhcp4.Options{
|
|
dhcp4.OptionSubnetMask: DHCPMask,
|
|
dhcp4.OptionRouter: DHCPRouterIP,
|
|
dhcp4.OptionDomainNameServer: DHCPDNSIP,
|
|
}.SelectOrderOrAll(reqOpt[dhcp4.OptionParameterRequestList])
|
|
|
|
// Creating the full packet layer by layer
|
|
buf := gopacket.NewSerializeBuffer()
|
|
opts := gopacket.SerializeOptions{
|
|
ComputeChecksums: true,
|
|
FixLengths: true,
|
|
}
|
|
eth := layers.Ethernet{
|
|
SrcMAC: DHCPMAC,
|
|
DstMAC: dstMAC,
|
|
EthernetType: layers.EthernetTypeIPv4,
|
|
}
|
|
ipv4 := layers.IPv4{
|
|
Version: 4,
|
|
TTL: 128,
|
|
Protocol: layers.IPProtocolUDP,
|
|
SrcIP: DHCPIP,
|
|
DstIP: net.IPv4bcast,
|
|
}
|
|
udp := layers.UDP{
|
|
SrcPort: 67,
|
|
DstPort: 68,
|
|
}
|
|
dhcp := dhcp4.ReplyPacket(req, mt, DHCPIP, lease, 24*time.Hour, opt)
|
|
if err := udp.SetNetworkLayerForChecksum(&ipv4); err != nil {
|
|
log.Error("Error building DHCP response:", err)
|
|
}
|
|
if err := gopacket.SerializeLayers(buf, opts, ð, &ipv4, &udp, gopacket.Payload(dhcp)); err != nil {
|
|
log.Error("Error serializing DHCP response:", err)
|
|
}
|
|
packetData := buf.Bytes()
|
|
|
|
// Sending layer through VM's pipe
|
|
packetLength := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(packetLength, uint16(len(packetData)))
|
|
|
|
if _, err := VmWriter.Write(packetLength); err != nil {
|
|
log.Error("Error writing DHCP response length", err)
|
|
}
|
|
if _, err := VmWriter.Write(packetData); err != nil {
|
|
log.Error("Error writing DHCP response data", err)
|
|
}
|
|
}
|
|
|
|
// sendDHCPRequest creates a request DHCP packet for the server and sends it
|
|
func sendDHCPRequest(mt dhcp4.MessageType, reqIP net.IP) {
|
|
log.Info("Sending DHCP request: ", mt)
|
|
if mt == dhcp4.Discover {
|
|
DHCPXId = 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, DHCPXId, 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()
|
|
|
|
// 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)
|
|
}
|
|
}
|