func fragment(eth layers.Ethernet, ip layers.IPv4, pmtu int, frame *ForwardedFrame, forward func(*ForwardedFrame)) error { // We are not doing any sort of NAT, so we don't need to worry // about checksums of IP payload (eg UDP checksum). headerSize := int(ip.IHL) * 4 // &^ is bit clear (AND NOT). So here we're clearing the lowest 3 // bits. maxSegmentSize := (pmtu - headerSize) &^ 7 opts := gopacket.SerializeOptions{ FixLengths: false, ComputeChecksums: true} payloadSize := int(ip.Length) - headerSize payload := ip.BaseLayer.Payload[:payloadSize] offsetBase := int(ip.FragOffset) << 3 origFlags := ip.Flags ip.Flags = ip.Flags | layers.IPv4MoreFragments ip.Length = uint16(headerSize + maxSegmentSize) if eth.EthernetType == layers.EthernetTypeLLC { // using LLC, so must set eth length correctly. eth length // is just the length of the payload eth.Length = ip.Length } else { eth.Length = 0 } for offset := 0; offset < payloadSize; offset += maxSegmentSize { var segmentPayload []byte if len(payload) <= maxSegmentSize { // last one segmentPayload = payload ip.Length = uint16(len(payload) + headerSize) ip.Flags = origFlags if eth.EthernetType == layers.EthernetTypeLLC { eth.Length = ip.Length } else { eth.Length = 0 } } else { segmentPayload = payload[:maxSegmentSize] payload = payload[maxSegmentSize:] } ip.FragOffset = uint16((offset + offsetBase) >> 3) buf := gopacket.NewSerializeBuffer() segPayload := gopacket.Payload(segmentPayload) err := gopacket.SerializeLayers(buf, opts, ð, &ip, &segPayload) if err != nil { return err } // make copies of the frame we received segFrame := *frame segFrame.frame = buf.Bytes() forward(&segFrame) } return nil }
func testSerialization(t *testing.T, p gopacket.Packet, data []byte) { // Test re-serialization. slayers := []gopacket.SerializableLayer{} for _, l := range p.Layers() { slayers = append(slayers, l.(gopacket.SerializableLayer)) if h, ok := l.(canSetNetLayer); ok { if err := h.SetNetworkLayerForChecksum(p.NetworkLayer()); err != nil { t.Fatal("can't set network layer:", err) } } } for _, opts := range []gopacket.SerializeOptions{ gopacket.SerializeOptions{}, gopacket.SerializeOptions{FixLengths: true}, gopacket.SerializeOptions{ComputeChecksums: true}, gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}, } { buf := gopacket.NewSerializeBuffer() err := gopacket.SerializeLayers(buf, opts, slayers...) if err != nil { t.Errorf("unable to reserialize layers with opts %#v: %v", opts, err) } else if !bytes.Equal(buf.Bytes(), data) { t.Errorf("serialization failure with opts %#v:\n---want---\n%v\n---got---\n%v\nBASH-colorized diff, want->got:\n%v", opts, hex.Dump(data), hex.Dump(buf.Bytes()), diffString(data, buf.Bytes())) } } }
func (dec *EthernetDecoder) sendICMPFragNeeded(mtu int, sendFrame func([]byte) error) error { buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true} ipHeaderSize := int(dec.ip.IHL) * 4 // IHL is the number of 32-byte words in the header payload := gopacket.Payload(dec.ip.BaseLayer.Contents[:ipHeaderSize+8]) err := gopacket.SerializeLayers(buf, opts, &layers.Ethernet{ SrcMAC: dec.eth.DstMAC, DstMAC: dec.eth.SrcMAC, EthernetType: dec.eth.EthernetType}, &layers.IPv4{ Version: 4, TOS: dec.ip.TOS, Id: 0, Flags: 0, FragOffset: 0, TTL: 64, Protocol: layers.IPProtocolICMPv4, DstIP: dec.ip.SrcIP, SrcIP: dec.ip.DstIP}, &layers.ICMPv4{ TypeCode: 0x304, Id: 0, Seq: uint16(mtu)}, &payload) if err != nil { return err } log.Printf("Sending ICMP 3,4 (%v -> %v): PMTU= %v\n", dec.ip.DstIP, dec.ip.SrcIP, mtu) return sendFrame(buf.Bytes()) }
func (dec *EthernetDecoder) formICMPMTUPacket(mtu int) ([]byte, error) { buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true} ipHeaderSize := int(dec.ip.IHL) * 4 // IHL is the number of 32-byte words in the header payload := gopacket.Payload(dec.ip.BaseLayer.Contents[:ipHeaderSize+8]) err := gopacket.SerializeLayers(buf, opts, &layers.Ethernet{ SrcMAC: dec.eth.DstMAC, DstMAC: dec.eth.SrcMAC, EthernetType: dec.eth.EthernetType}, &layers.IPv4{ Version: 4, TOS: dec.ip.TOS, Id: 0, Flags: 0, FragOffset: 0, TTL: 64, Protocol: layers.IPProtocolICMPv4, DstIP: dec.ip.SrcIP, SrcIP: dec.ip.DstIP}, &layers.ICMPv4{ TypeCode: 0x304, Id: 0, Seq: uint16(mtu)}, &payload) if err != nil { return []byte{}, err } return buf.Bytes(), nil }
// writeARP writes an ARP request for each address on our local network to the // pcap handle. func writeARP(handle *pcap.Handle, iface *net.Interface, addr *net.IPNet) error { // Set up all the layers' fields we can. eth := layers.Ethernet{ SrcMAC: iface.HardwareAddr, DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, EthernetType: layers.EthernetTypeARP, } arp := layers.ARP{ AddrType: layers.LinkTypeEthernet, Protocol: layers.EthernetTypeIPv4, HwAddressSize: 6, ProtAddressSize: 4, Operation: layers.ARPRequest, SourceHwAddress: []byte(iface.HardwareAddr), SourceProtAddress: []byte(addr.IP), DstHwAddress: []byte{0, 0, 0, 0, 0, 0}, } // Set up buffer and options for serialization. buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, } // Send one packet for every address. for ip := range ips(addr) { arp.DstProtAddress = []byte(ip) gopacket.SerializeLayers(buf, opts, ð, &arp) if err := handle.WritePacketData(buf.Bytes()); err != nil { return err } } return nil }
// newScanner creates a new scanner for a given destination IP address, using // router to determine how to route packets to that IP. func newScanner(ip net.IP, router routing.Router) (*scanner, error) { s := &scanner{ dst: ip, opts: gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, }, buf: gopacket.NewSerializeBuffer(), } // Figure out the route to the IP. iface, gw, src, err := router.Route(ip) if err != nil { return nil, err } log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src) s.gw, s.src, s.iface = gw, src, iface // Open the handle for reading/writing. // Note we could very easily add some BPF filtering here to greatly // decrease the number of packets we have to look at when getting back // scan results. handle, err := pcap.OpenLive(iface.Name, 65536, true, time.Millisecond) if err != nil { return nil, err } s.handle = handle return s, nil }
func BenchmarkSerializeTcpFixLengthsComputeChecksums(b *testing.B) { slayers := getSerializeLayers() buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true} for i := 0; i < b.N; i++ { gopacket.SerializeLayers(buf, opts, slayers...) } }
func BenchmarkSerializeTcpNoOptions(b *testing.B) { slayers := getSerializeLayers() buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{} for i := 0; i < b.N; i++ { gopacket.SerializeLayers(buf, opts, slayers...) } }
/*Serialize helps to serialize an IPv4 packet that has been tampered with. The IP checksum is recomputed, and the whole packet is concatenated together into a byte slice that can be passed to netfilter.*/ func Serialize(ipLayer *layers.IPv4) ([]byte, error) { /*Write the IPv4 header into a gopacket buffer*/ buf := gopacket.NewSerializeBuffer() err := ipLayer.SerializeTo(buf, gopacket.SerializeOptions{FixLengths: false, ComputeChecksums: true}) if err != nil { return nil, err } /*Write the gopacket buffer and the payload into a byte buffer, concatenating the entire packet together.*/ var buf2 bytes.Buffer buf2.Write(buf.Bytes()) buf2.Write(ipLayer.Payload) return buf2.Bytes(), nil }
func UpdatePkt(p *Packet) { buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ ComputeChecksums: true, FixLengths: true, } if len(p.app) > 0 { appbuf, _ := buf.PrependBytes(len(p.app)) copy(appbuf, p.app) } if p.tcp != nil { p.tcp.SetNetworkLayerForChecksum(p.ip) p.tcp.SerializeTo(buf, opts) } else { p.udp.SetNetworkLayerForChecksum(p.ip) p.udp.SerializeTo(buf, opts) } p.ip.SerializeTo(buf, opts) p.eth.SerializeTo(buf, opts) p.data = buf.Bytes() }
func NewRawUDPSender(conn *LocalConnection) (*RawUDPSender, error) { ipSocket, err := dialIP(conn) if err != nil { return nil, err } udpHeader := &layers.UDP{SrcPort: layers.UDPPort(Port)} ipBuf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ FixLengths: true, // UDP header is calculated with a phantom IP // header. Yes, it's totally nuts. Thankfully, for UDP // over IPv4, the checksum is optional. It's not // optional for IPv6, but we'll ignore that for // now. TODO ComputeChecksums: false} return &RawUDPSender{ ipBuf: ipBuf, opts: opts, udpHeader: udpHeader, socket: ipSocket, conn: conn}, nil }
//sendPacket generates & sends a packet of arbitrary size to a specific destination. //The size specified should be larger then 40bytes. func sendPacket(sourceIP string, destinationIP string, size int, message string, appID int, chanID int, icmpType layers.ICMPv4TypeCode) []byte { var payloadSize int if size < 28 { //Unable to create smaller packets. payloadSize = 0 } else { payloadSize = size - 28 } //Convert IP to 4bit representation srcIP := net.ParseIP(sourceIP).To4() dstIP := net.ParseIP(destinationIP).To4() //IP Layer ip := layers.IPv4{ SrcIP: srcIP, DstIP: dstIP, Version: 4, TTL: 64, Protocol: layers.IPProtocolICMPv4, } icmp := layers.ICMPv4{ TypeCode: icmpType, } opts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, } ipHeaderBuf := gopacket.NewSerializeBuffer() err := ip.SerializeTo(ipHeaderBuf, opts) if err != nil { panic(err) } //Set "Don't Fragment"-Flag in Header ipHeader, err := ipv4.ParseHeader(ipHeaderBuf.Bytes()) ipHeader.Flags |= ipv4.DontFragment if err != nil { panic(err) } payloadBuf := gopacket.NewSerializeBuffer() //Influence the payload size payload := gopacket.Payload(generatePayload(payloadSize, ","+strconv.Itoa(appID)+","+strconv.Itoa(chanID)+","+message+",")) err = gopacket.SerializeLayers(payloadBuf, opts, &icmp, payload) if err != nil { panic(err) } //Send packet var packetConn net.PacketConn var rawConn *ipv4.RawConn packetConn, err = net.ListenPacket("ip4:icmp", srcIP.String()) if err != nil { panic(err) } rawConn, err = ipv4.NewRawConn(packetConn) if err != nil { panic(err) } err = rawConn.WriteTo(ipHeader, payloadBuf.Bytes(), nil) return append(ipHeaderBuf.Bytes(), payloadBuf.Bytes()...) }
func main() { flag.Parse() args := flag.Args() if len(args) != 2 { fmt.Printf("Usage: %s <ip> <port>\n", os.Args[0]) os.Exit(-1) } // parse the destination host and port from the command line args dstip := net.ParseIP(args[0]).To4() dport_, err := strconv.ParseInt(args[1], 10, 16) if err != nil { panic(err) } dport := layers.TCPPort(dport_) // get our local ip. srcip, err := localIP(dstip) if err != nil { panic(err) } // Our IPv4 header ip := &layers.IPv4{ Version: 4, IHL: 5, TOS: 0, Length: 0, // FIX Id: 12345, FragOffset: 16384, TTL: 64, Protocol: layers.IPProtocolTCP, Checksum: 0, SrcIP: srcip, DstIP: dstip, } // Our TCP header tcp := &layers.TCP{ SrcPort: 45677, DstPort: dport, Seq: 1105024978, Ack: 0, SYN: true, Window: 14600, Checksum: 0, Urgent: 0, } tcp.DataOffset = uint8(unsafe.Sizeof(tcp)) tcp.SetNetworkLayerForChecksum(ip) buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ ComputeChecksums: true, // automatically compute checksums } err = ip.SerializeTo(buf, opts) if err != nil { panic(err) } err = tcp.SerializeTo(buf, opts) if err != nil { panic(err) } conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0") if err != nil { panic(err) } _, err = conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}) if err != nil { panic(err) } var b []byte b = make([]byte, 152) n, addr, err := conn.ReadFrom(b) if err != nil { panic(err) } if addr.String() == dstip.String() { // Decode a packet packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default) // Get the TCP layer from this packet if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { tcp, _ := tcpLayer.(*layers.TCP) //fmt.Printf("SYN: %v, ACK: %v, RST: %v\n", tcp.SYN, tcp.ACK, tcp.RST) if tcp.SYN && tcp.ACK { fmt.Printf("Port %d is OPEN\n", dport) } else { fmt.Printf("Port %d is CLOSED\n", dport) } } } }
// Sends an ARP request packet to determine the MAC address of an IP func remoteMac(dev string, srcmac net.HardwareAddr, srcip, dstip net.IP) (net.HardwareAddr, error) { var dstmac net.HardwareAddr eth := &layers.Ethernet{ SrcMAC: srcmac, DstMAC: net.HardwareAddr{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, EthernetType: layers.EthernetTypeARP, } arp := &layers.ARP{ AddrType: layers.LinkTypeEthernet, Protocol: layers.EthernetTypeIPv4, HwAddressSize: 6, ProtAddressSize: 4, Operation: 1, //arp request SourceHwAddress: srcmac, SourceProtAddress: srcip, DstHwAddress: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DstProtAddress: dstip, } buf := gopacket.NewSerializeBuffer() err := gopacket.SerializeLayers( buf, gopacket.SerializeOptions{ ComputeChecksums: true, // automatically compute checksums FixLengths: true, }, eth, arp, ) if err != nil { return dstmac, err } handle, err := pcap.OpenLive(`rpcap://`+dev, 65535, true, time.Second*1) if err != nil { return dstmac, err } defer handle.Close() var wg sync.WaitGroup handle.SetBPFFilter(fmt.Sprintf("arp and ether host %s", srcmac.String())) packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) macchan := make(chan net.HardwareAddr, 1) wg.Add(1) go func() { stop := false go func() { <-time.After(time.Second * 2) stop = true }() for { if stop { break } packet, err := packetSource.NextPacket() if err == io.EOF { break } else if err != nil { //log.Println("Error:", err) continue } if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil { arp_, _ := arpLayer.(*layers.ARP) if bytes.Equal(arp_.SourceProtAddress, dstip) && arp_.Operation == 2 { macchan <- arp_.SourceHwAddress break } } } wg.Done() }() err = handle.WritePacketData(buf.Bytes()) if err != nil { return dstmac, err } wg.Wait() dstmac = <-macchan return dstmac, nil }
func main() { flag.Parse() args := flag.Args() if len(args) != 2 { log.Printf("Usage: %s <ip> <port>\n", os.Args[0]) os.Exit(-1) } // parse the destination host and port from the command line args dstip := net.ParseIP(args[0]).To4() dport_, err := strconv.ParseInt(args[1], 10, 16) if err != nil { log.Fatal(err) } dport := layers.TCPPort(dport_) sport := layers.TCPPort(5000) // get our local ip. srcip, err := localIP(dstip) if err != nil { log.Fatal(err) } devs, err := pcap.FindAllDevs() if err != nil { log.Fatal(err) } dev := "" for _, d := range devs { for _, a := range d.Addresses { if bytes.Equal(a.IP, srcip) { dev = d.Name } } // if d.Description == "Realtek PCIe GBE Family Controller" { // fmt.Println(d.Name) // dev = d.Name // } // fmt.Println(dev.Description) } if dev == "" { log.Fatal("Could not find the appropriate adapter device") } srcmac, err := localMac(dev) if err != nil { log.Fatal(err) } dstmac, err := remoteMac(dev, srcmac, srcip, dstip) if err != nil { log.Fatal(err) } eth := &layers.Ethernet{ SrcMAC: srcmac, DstMAC: dstmac, EthernetType: layers.EthernetTypeIPv4, } // Our IPv4 header ip := &layers.IPv4{ Version: 4, IHL: 5, TOS: 0, Length: 20, // FIX Id: 2, Flags: layers.IPv4DontFragment, FragOffset: 0, //16384, TTL: 3, //64, Protocol: layers.IPProtocolTCP, Checksum: 0, SrcIP: srcip, DstIP: dstip, } // Our TCP header tcp := &layers.TCP{ SrcPort: sport, DstPort: dport, Seq: 0, Ack: 0, SYN: true, Window: 64240, Checksum: 0, Urgent: 0, } tcp.DataOffset = 5 // uint8(unsafe.Sizeof(tcp)) tcp.SetNetworkLayerForChecksum(ip) buf := gopacket.NewSerializeBuffer() err = gopacket.SerializeLayers( buf, gopacket.SerializeOptions{ ComputeChecksums: true, // automatically compute checksums FixLengths: true, }, eth, ip, tcp, ) if err != nil { log.Fatal(err) } handle, err := pcap.OpenLive(`rpcap://`+dev, 65535, true, time.Second*1) if err != nil { log.Fatal(err) } defer handle.Close() var wg sync.WaitGroup handle.SetBPFFilter(fmt.Sprintf("tcp and host %s and host %s and port %d and port %d", srcip.String(), dstip.String(), sport, dport)) packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) wg.Add(1) go func() { stop := false go func() { <-time.After(time.Second * 2) stop = true }() for { if stop { break } packet, err := packetSource.NextPacket() if err == io.EOF { break } else if err != nil { //log.Println("Error:", err) continue } if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { tcp, _ := tcpLayer.(*layers.TCP) if tcp.SrcPort == dport && tcp.DstPort == sport { if tcp.SYN && tcp.ACK { fmt.Printf("Port %d is OPEN\n", dport_) } else { fmt.Printf("Port %d is CLOSED\n", dport_) } break } //fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort) } } wg.Done() }() err = handle.WritePacketData(buf.Bytes()) if err != nil { log.Fatal(err) } wg.Wait() }
//Detectinitcwnd attempts to detect the initial congession window of an http endpoint. //First does a 3 way tcp handshake, sends GET request and then does not ack any response while measuring the packets received. This allows us to see how much data the server can send without acknowledgement. func Detectinitcwnd(host, url string, dstip net.IP) (pkt_count, payload_size int, fullpayload []byte, err error) { pldata := []byte(fmt.Sprintf("GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", url, host)) var dstport layers.TCPPort dstport = layers.TCPPort(80) srcip, sport := localIPPort(dstip) srcport := layers.TCPPort(sport) log.Printf("using srcip: %v", srcip.String()) log.Printf("using dstip: %v", dstip.String()) // Our IP header... not used, but necessary for TCP checksumming. ip := &layers.IPv4{ SrcIP: srcip, DstIP: dstip, Protocol: layers.IPProtocolTCP, } //layers.TCPOption{3, 3, []byte{7}} maybe for window scaling... dunno tcpopts := []layers.TCPOption{layers.TCPOption{2, 4, []byte{5, 172}}} //Set MSS 1452 // Our TCP header tcp := &layers.TCP{ SrcPort: srcport, DstPort: dstport, Seq: 1105024978, SYN: true, Window: 65535, Options: tcpopts, } tcp.SetNetworkLayerForChecksum(ip) // Serialize. Note: we only serialize the TCP layer, because the // socket we get with net.ListenPacket wraps our data in IPv4 packets // already. We do still need the IP layer to compute checksums // correctly, though. buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ ComputeChecksums: true, FixLengths: true, } err = gopacket.SerializeLayers(buf, opts, tcp) if err != nil { return } var out1 bytes.Buffer iptset := exec.Command("iptables", "-A", "OUTPUT", "-p", "tcp", "--tcp-flags", "RST", "RST", "-s", srcip.String(), "--sport", porttoint(srcport), "--dport", porttoint(dstport), "-j", "DROP") iptset.Stderr = &out1 log.Println(iptset) err = iptset.Run() if err != nil { return } log.Println(out1.String()) iptrem := exec.Command("iptables", "-D", "OUTPUT", "-p", "tcp", "--tcp-flags", "RST", "RST", "-s", srcip.String(), "--sport", porttoint(srcport), "--dport", porttoint(dstport), "-j", "DROP") conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0") if err != nil { return } defer func() { fmt.Println(iptrem) var out bytes.Buffer iptrem.Stderr = &out err = iptrem.Run() if err != nil { log.Println(err) } fmt.Printf(out.String()) log.Println("Removed iptable rule") //Now RST should be allowed... send it rst_pkt := &layers.TCP{ SrcPort: srcport, DstPort: dstport, Seq: 1105024980, Window: 65535, RST: true, } rst_pkt.SetNetworkLayerForChecksum(ip) if err := gopacket.SerializeLayers(buf, opts, rst_pkt); err != nil { //Shadowing err since we dont care log.Println(err) } if _, err := conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}); err != nil { //Shadowing err since we dont care log.Println(err) } }() log.Println("writing request") _, err = conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}) if err != nil { return } // Set deadline so we don't wait forever. err = conn.SetDeadline(time.Now().Add(15 * time.Second)) if err != nil { return } //Capture synack from our syn, return the ack value ack, err := getack(conn, srcport, dstip.String()) if err != nil { log.Println(err) return } else { //Prepare http request, ack the synack payload := &layers.TCP{ SrcPort: srcport, DstPort: dstport, Seq: 1105024979, ACK: true, Window: 65535, Ack: ack + 1, } payload.SetNetworkLayerForChecksum(ip) if err := gopacket.SerializeLayers(buf, opts, payload, gopacket.Payload(pldata)); err != nil { log.Fatal(err) } if _, err := conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}); err != nil { log.Fatal(err) } pkt_count, payload_size, fullpayload = listenandcount(conn, dstip.String(), srcport) log.Println("Initcwnd: ", pkt_count) log.Println("Data: ", payload_size) return } return }