func fragment(eth layers.Ethernet, ip layers.IPv4, mtu int, forward func([]byte)) 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 := (mtu - 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 } forward(buf.Bytes()) } return nil }
/* Adds the SIFF header to a packet, or modifies it in the case that it already exists. Pass in the NFPacket, the flags (bitwise OR them if you need both), and the capabilities and capability updates arrays. If only IsSiff is set, just fill the last 4 bytes with dummy data, it'll be ignored. If you want to update specific fields, then use the [update function name here] function */ func setSiffFields(packet *netfilter.NFPacket, flags uint8, capabilities []byte, updoots []byte) { var ipLayer *layers.IPv4 var option [1]layers.IPv4Option option[0].OptionType = 86 option[0].OptionLength = 8 /* Get the IPv4 layer, and if it doesn't exist, keep doing shit I can't be arsed for proper response outside the bounds of this project */ if layer := packet.Packet.Layer(layers.LayerTypeIPv4); layer != nil { ipLayer = layer.(*layers.IPv4) } else { // maybe do something? } /* Modify the ip layer information */ var IHLchange uint16 = uint16(ipLayer.IHL) // compute new IHL and length if (flags & CapabilityUpdate) == CapabilityUpdate { ipLayer.IHL = 8 option[0].OptionLength = 12 } else if (flags&IsSiff) == IsSiff || (flags&Exp) == Exp { ipLayer.IHL = 7 } else { ipLayer.IHL = 5 } IHLchange = uint16(ipLayer.IHL) - IHLchange if IHLchange != 0 { ipLayer.Length += IHLchange * 4 } if (flags & Evil) == Evil { // set the evil flag. If we do this, we don't need to do anything else, // since evil packets are legacy, and don't have other flags ipLayer.Flags |= layers.IPv4EvilBit } else { // set the flags option option[0].OptionData = []byte{0, 0} if (flags & Exp) == Exp { option[0].OptionData[0] = byte(Exp) } if (flags & CapabilityUpdate) == CapabilityUpdate { option[0].OptionData[0] |= byte(IsSiff | CapabilityUpdate) } else if (flags & IsSiff) == IsSiff { option[0].OptionData[0] |= byte(IsSiff) } // handle the options if flags != 0 { for _, b := range capabilities { option[0].OptionData = append(option[0].OptionData, b) } } if (flags & CapabilityUpdate) == CapabilityUpdate { for _, b := range updoots { option[0].OptionData = append(option[0].OptionData, b) } } // add options if flags != 0 { ipLayer.Options = append([]layers.IPv4Option{option[0]}, ipLayer.Options...) } } // we're done }