| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- package packetparse
- import (
- "github.com/google/gopacket"
- "github.com/google/gopacket/layers"
- "github.com/v2fly/v2ray-core/v5/common/net"
- )
- var (
- errNotIPPacket = newError("not an IP packet")
- errNotUDPPacket = newError("not a UDP packet")
- )
- var nullDestination = net.UnixDestination(net.DomainAddress("null"))
- func TryParseAsUDPPacket(packet []byte) (src, dst net.Destination, data []byte, err error) {
- parsedPacket := gopacket.NewPacket(packet, layers.LayerTypeIPv4, gopacket.DecodeOptions{
- Lazy: true,
- NoCopy: false,
- SkipDecodeRecovery: false,
- DecodeStreamsAsDatagrams: false,
- })
- var srcIP net.Address
- var dstIP net.Address
- ipv4Layer := parsedPacket.Layer(layers.LayerTypeIPv4)
- if ipv4Layer == nil {
- parsedPacketAsIPv6 := gopacket.NewPacket(packet, layers.LayerTypeIPv6, gopacket.DecodeOptions{
- Lazy: true,
- NoCopy: false,
- SkipDecodeRecovery: false,
- DecodeStreamsAsDatagrams: false,
- })
- ipv6Layer := parsedPacketAsIPv6.Layer(layers.LayerTypeIPv6)
- if ipv6Layer == nil {
- return nullDestination, nullDestination, nil, errNotIPPacket
- }
- ipv6 := ipv6Layer.(*layers.IPv6)
- srcIP = net.IPAddress(ipv6.SrcIP)
- dstIP = net.IPAddress(ipv6.DstIP)
- parsedPacket = parsedPacketAsIPv6
- } else {
- ipv4 := ipv4Layer.(*layers.IPv4)
- srcIP = net.IPAddress(ipv4.SrcIP)
- dstIP = net.IPAddress(ipv4.DstIP)
- }
- udpLayer := parsedPacket.Layer(layers.LayerTypeUDP)
- if udpLayer == nil {
- return nullDestination, nullDestination, nil, errNotUDPPacket
- }
- udp := udpLayer.(*layers.UDP)
- srcPort := net.Port(udp.SrcPort)
- dstPort := net.Port(udp.DstPort)
- src = net.UDPDestination(srcIP, srcPort)
- dst = net.UDPDestination(dstIP, dstPort)
- data = udp.Payload
- return // nolint: nakedret
- }
- func TryConstructUDPPacket(src, dst net.Destination, data []byte) ([]byte, error) {
- if src.Address.Family().IsIPv4() && dst.Address.Family().IsIPv4() {
- return constructIPv4UDPPacket(src, dst, data)
- }
- if src.Address.Family().IsIPv6() && dst.Address.Family().IsIPv6() {
- return constructIPv6UDPPacket(src, dst, data)
- }
- return nil, newError("not supported")
- }
- func constructIPv4UDPPacket(src, dst net.Destination, data []byte) ([]byte, error) {
- ipv4 := &layers.IPv4{
- Version: 4,
- Protocol: layers.IPProtocolUDP,
- SrcIP: src.Address.IP(),
- DstIP: dst.Address.IP(),
- TTL: 64, // set TTL to a reasonable non-zero value to allow non-local routing
- }
- udp := &layers.UDP{
- SrcPort: layers.UDPPort(src.Port),
- DstPort: layers.UDPPort(dst.Port),
- }
- err := udp.SetNetworkLayerForChecksum(ipv4)
- if err != nil {
- return nil, err
- }
- buffer := gopacket.NewSerializeBuffer()
- if err := gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{
- FixLengths: true,
- ComputeChecksums: true,
- }, ipv4, udp, gopacket.Payload(data)); err != nil {
- return nil, err
- }
- return buffer.Bytes(), nil
- }
- func constructIPv6UDPPacket(src, dst net.Destination, data []byte) ([]byte, error) {
- ipv6 := &layers.IPv6{
- Version: 6,
- NextHeader: layers.IPProtocolUDP,
- SrcIP: src.Address.IP(),
- DstIP: dst.Address.IP(),
- HopLimit: 64,
- }
- udp := &layers.UDP{
- SrcPort: layers.UDPPort(src.Port),
- DstPort: layers.UDPPort(dst.Port),
- }
- err := udp.SetNetworkLayerForChecksum(ipv6)
- if err != nil {
- return nil, err
- }
- buffer := gopacket.NewSerializeBuffer()
- if err := gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{
- FixLengths: true,
- ComputeChecksums: true,
- }, ipv6, udp, gopacket.Payload(data)); err != nil {
- return nil, err
- }
- return buffer.Bytes(), nil
- }
|