Example #1
1
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, &eth, &ip, &segPayload)
		if err != nil {
			return err
		}
		// make copies of the frame we received
		segFrame := *frame
		segFrame.frame = buf.Bytes()
		forward(&segFrame)
	}
	return nil
}
Example #2
0
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())
}
Example #3
0
func (sender *RawUDPSender) Send(msg []byte) error {
	payload := gopacket.Payload(msg)
	sender.udpHeader.DstPort = layers.UDPPort(sender.conn.RemoteUDPAddr().Port)

	err := gopacket.SerializeLayers(sender.ipBuf, sender.opts, sender.udpHeader, &payload)
	if err != nil {
		return err
	}
	packet := sender.ipBuf.Bytes()
	_, err = sender.socket.Write(packet)
	if err == nil || PosixError(err) != syscall.EMSGSIZE {
		return err
	}
	f, err := sender.socket.File()
	if err != nil {
		return err
	}
	defer f.Close()
	fd := int(f.Fd())
	log.Println("EMSGSIZE on send, expecting PMTU update (IP packet was",
		len(packet), "bytes, payload was", len(msg), "bytes)")
	pmtu, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_MTU)
	if err != nil {
		return err
	}
	return MsgTooBigError{PMTU: pmtu}
}
Example #4
0
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
}
//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()...)
}
Example #6
0
//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
}