diff --git a/proxy/go.mod b/proxy/go.mod index aa6984a..c329bef 100644 --- a/proxy/go.mod +++ b/proxy/go.mod @@ -4,5 +4,6 @@ go 1.13 require ( github.com/google/gopacket v1.1.19 + github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771 github.com/sirupsen/logrus v1.8.1 ) diff --git a/proxy/go.sum b/proxy/go.sum index 48f926c..2014af6 100644 --- a/proxy/go.sum +++ b/proxy/go.sum @@ -1,41 +1,26 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc h1:m7rJJJeXrYCFpsxXYapkDW53wJCDmf9bsIXUg0HoeQY= -github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc/go.mod h1:eOj1DDj3NAZ6yv+WafaKzY37MFZ58TdfIhQ+8nQbiis= -github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966 h1:O3p5UmisBhl3V6lgs4Vdfg8HpjzbWJPyOfGLdwVJSmI= -github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/sMJ6sNsFl6uCh85lkFGV8kLuIYJCRJLavVJwvg= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d h1:rjAS0af7FIYCScTtEU5KjIldC6qVaEScUJhABHC+ccM= -github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18 h1:zwOa3e/13D6veNIz6zzuqrd3eZEMF0dzD0AQWKcYSs4= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771 h1:t2c2B9g1ZVhMYduqmANSEGVD3/1WlsrEYNPtVoFlENk= +github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771/go.mod h1:0AqAH3ZogsCrvrtUpvc6EtVKbc3w6xwZhkvGLuqyi3o= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4 h1:3i7qG/aA9NUAzdnJHfhgxSKSmxbAebomYR5IZgFbC5Y= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/proxy/main.go b/proxy/main.go index 6fa233e..b53223c 100644 --- a/proxy/main.go +++ b/proxy/main.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/google/gopacket" "github.com/google/gopacket/layers" + dhcp "github.com/krolaw/dhcp4" log "github.com/sirupsen/logrus" "io" "net" @@ -109,10 +110,17 @@ func pipeForward(prefix string) { log.Debug("Start packet") filterMAC(prefix, &frame.DstMAC, &frame.SrcMAC, frame.LayerType()) - // Handle IPv6 packet + // 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 && !Passthrough { + handleDHCP(dhcpLayer.LayerContents(), frame.DstMAC, prefix) + continue + } + filterIP(prefix, &ipv4Packet.DstIP, &ipv4Packet.SrcIP, ipv4Packet.LayerType()) // Handle ICMP packet (based on IPv4) @@ -121,13 +129,6 @@ func pipeForward(prefix string) { log.Debug(prefix, "ICMP Type ", icmpPacket.TypeCode) } - // Handle DHCP packet (based on IPv4) - drop for now - if dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4); dhcpLayer != nil && !Passthrough { - //dhcpPacket, _ := dhcpLayer.(*layers.DHCPv4) - log.Info(prefix, "DHCP packet dropped") - continue - } - // Handle TCP packet if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { tcpPacket, _ := tcpLayer.(*layers.TCP) @@ -175,7 +176,7 @@ func pipeForward(prefix string) { if isInteresting { util.WriteBinary(fmt.Sprintf("/tmp/pck_%di.dat", time.Now().Unix()), frameBytes) util.WriteBinary(fmt.Sprintf("/tmp/pck_%do.dat", time.Now().Unix()), newFrameBytes) - //util.WritePcap("xyz.pcap", packet.Data(), packet.Metadata().CaptureInfo) + //util.WritePcapNg("xyz.pcap", packet.Data(), packet.Metadata().CaptureInfo) } // Forward modified frame to other plug @@ -210,6 +211,9 @@ func filterIP(prefix string, dst interface{}, src interface{}, context gopacket. return } else if prefix == cmd.Out { if isIp { + if!ip.IsGlobalUnicast() { + return + } OldIP = *ip } else if isBs { OldIP = *bs @@ -267,4 +271,107 @@ func filterMAC(prefix string, dst interface{}, src interface{}, context gopacket *bs = newVal log.Debugf("%s%s %s MAC %s changed to %s", prefix, context, which, condVal, newVal) } +} + +func handleDHCP(content []byte, srcMAC net.HardwareAddr, prefix string) { + req := dhcp.Packet(content) + if req.HLen() > 16 { // Invalid size + log.Error(prefix, "Invalid DHCP size") + return + } + options := req.ParseOptions() + var reqType dhcp.MessageType + if t := options[dhcp.OptionDHCPMessageType]; len(t) != 1 { + log.Error(prefix, "Invalid DHCP message type") + return + } else { + reqType = dhcp.MessageType(t[0]) + if reqType < dhcp.Discover || reqType > dhcp.Inform { + log.Error(prefix, "Invalid DHCP message type: ", reqType) + return + } + } + log.Debug(prefix, "DHCP message registered: ", reqType) + if prefix == cmd.Out { + switch reqType { + case dhcp.Discover: + if OldIP == nil { + log.Fatal(prefix, "DHCPDISCOVER but not previous address is known") + } + sendDHCPReply(req, dhcp.Offer, OldIP, options, srcMAC) + case dhcp.Request: + reqIP := net.IP(options[dhcp.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, dhcp.ACK, reqIP, options, srcMAC) + default: + return + } + } else { + // TODO: talk to dhcp server + } +} + +// sendDHCPReply creates a response dhcp packet and sends it +func sendDHCPReply(req dhcp.Packet, mt dhcp.MessageType, lease net.IP, reqOpt dhcp.Options, dstMAC net.HardwareAddr) { + log.Info("Sending DHCP response: ", mt, lease) + // Getting the options + serverIP := []byte{10, 0, 0, 1} // TODO: serverIP + serverMAC := util.GenerateMac("") // TODO: server MAC + opt := dhcp.Options{ + dhcp.OptionSubnetMask: []byte{255, 255, 255, 0}, // TODO: subnet mask + dhcp.OptionRouter: serverIP, // TODO: Presuming Server is also your router + dhcp.OptionDomainNameServer: serverIP, // TODO: Presuming Server is also your DNS server + }.SelectOrderOrAll(reqOpt[dhcp.OptionParameterRequestList]) + + // Creating the full packet layer by layer + dhcplayer := dhcp.ReplyPacket(req, mt, serverIP, lease, 24 * time.Hour, opt) + buf := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{ + ComputeChecksums: true, + FixLengths: true, + + } + ipv4 := layers.IPv4{ + Version: 4, + TTL: 64, + Protocol: layers.IPProtocolUDP, + SrcIP: serverIP, + DstIP: lease, + } + udp := layers.UDP{ + SrcPort: 67, + DstPort: 68, + } + udp.SetNetworkLayerForChecksum(&ipv4) + err := gopacket.SerializeLayers(buf, opts, + &layers.Ethernet{ + SrcMAC: serverMAC, + DstMAC: dstMAC, + EthernetType: layers.EthernetTypeIPv4, + }, + &ipv4, + &udp, + gopacket.Payload(dhcplayer)) + if err != nil { + return + } + packetData := buf.Bytes() + + // Sending layer through VM's pipe + packetLength := make([]byte, 2) + binary.BigEndian.PutUint16(packetLength, uint16(len(packetData))) + + + util.WriteBinary(fmt.Sprintf("/tmp/dhcp_%d.dat", time.Now().Unix()), packetData) + util.WritePcap(fmt.Sprintf("/tmp/dhcp_%d.pcap", time.Now().Unix()), packetData) + util.WritePcap(fmt.Sprintf("/tmp/dhcp_%d2.pcap", time.Now().Unix()), packetData[36:]) + + VmWriter.Write(packetLength) + VmWriter.Write(packetData) } \ No newline at end of file diff --git a/proxy/proxy b/proxy/proxy index be759ae..2238eac 100755 Binary files a/proxy/proxy and b/proxy/proxy differ diff --git a/proxy/util/util.go b/proxy/util/util.go index f5af53a..93a80a1 100644 --- a/proxy/util/util.go +++ b/proxy/util/util.go @@ -10,10 +10,11 @@ import ( "net" "os" "strconv" + "time" ) -// WritePcap writes the provided data to a given pcap file -func WritePcap(file string, data []byte, ci gopacket.CaptureInfo) { +// WritePcapNg writes the provided data to a given pcap file +func WritePcapNg(file string, data []byte) { f, err := os.Create(file) if err != nil { log.Errorf("Error writing pcap file %s", file) @@ -26,9 +27,28 @@ func WritePcap(file string, data []byte, ci gopacket.CaptureInfo) { } defer r.Flush() + ci := gopacket.CaptureInfo{ + Timestamp: time.Now(), + CaptureLength: len(data), + Length: len(data), + } + err = r.WritePacket(ci, data) } +func WritePcap(file string, data []byte) { + f, _ := os.Create(file) + w := pcapgo.NewWriter(f) + w.WriteFileHeader(65536, layers.LinkTypeEthernet) // new file, must do this. + ci := gopacket.CaptureInfo{ + Timestamp: time.Now(), + CaptureLength: len(data), + Length: len(data), + } + w.WritePacket(ci, data) + f.Close() +} + // WriteBinary writes the provided data to a given binary file func WriteBinary(file string, data []byte) { if err := ioutil.WriteFile(file, data, 0644); err != nil { @@ -47,7 +67,7 @@ func WritePIDFile(filename string) { func GenerateMac(customMAC string) net.HardwareAddr { if customMAC != "" { - ret, _ := net.ParseMAC("52:54:00:12:34:aa") + ret, _ := net.ParseMAC(customMAC) return ret } buf := make([]byte, 6)