github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/tun/packetparse/udp.go (about) 1 package packetparse 2 3 import ( 4 "github.com/google/gopacket" 5 "github.com/google/gopacket/layers" 6 7 "github.com/v2fly/v2ray-core/v5/common/net" 8 ) 9 10 var ( 11 errNotIPPacket = newError("not an IP packet") 12 errNotUDPPacket = newError("not a UDP packet") 13 ) 14 15 var nullDestination = net.UnixDestination(net.DomainAddress("null")) 16 17 func TryParseAsUDPPacket(packet []byte) (src, dst net.Destination, data []byte, err error) { 18 parsedPacket := gopacket.NewPacket(packet, layers.LayerTypeIPv4, gopacket.DecodeOptions{ 19 Lazy: true, 20 NoCopy: false, 21 SkipDecodeRecovery: false, 22 DecodeStreamsAsDatagrams: false, 23 }) 24 25 var srcIP net.Address 26 var dstIP net.Address 27 ipv4Layer := parsedPacket.Layer(layers.LayerTypeIPv4) 28 29 if ipv4Layer == nil { 30 parsedPacketAsIPv6 := gopacket.NewPacket(packet, layers.LayerTypeIPv6, gopacket.DecodeOptions{ 31 Lazy: true, 32 NoCopy: false, 33 SkipDecodeRecovery: false, 34 DecodeStreamsAsDatagrams: false, 35 }) 36 ipv6Layer := parsedPacketAsIPv6.Layer(layers.LayerTypeIPv6) 37 if ipv6Layer == nil { 38 return nullDestination, nullDestination, nil, errNotIPPacket 39 } 40 ipv6 := ipv6Layer.(*layers.IPv6) 41 srcIP = net.IPAddress(ipv6.SrcIP) 42 dstIP = net.IPAddress(ipv6.DstIP) 43 44 parsedPacket = parsedPacketAsIPv6 45 } else { 46 ipv4 := ipv4Layer.(*layers.IPv4) 47 srcIP = net.IPAddress(ipv4.SrcIP) 48 dstIP = net.IPAddress(ipv4.DstIP) 49 } 50 51 udpLayer := parsedPacket.Layer(layers.LayerTypeUDP) 52 if udpLayer == nil { 53 return nullDestination, nullDestination, nil, errNotUDPPacket 54 } 55 udp := udpLayer.(*layers.UDP) 56 srcPort := net.Port(udp.SrcPort) 57 dstPort := net.Port(udp.DstPort) 58 59 src = net.UDPDestination(srcIP, srcPort) 60 dst = net.UDPDestination(dstIP, dstPort) 61 data = udp.Payload 62 return // nolint: nakedret 63 } 64 65 func TryConstructUDPPacket(src, dst net.Destination, data []byte) ([]byte, error) { 66 if src.Address.Family().IsIPv4() && dst.Address.Family().IsIPv4() { 67 return constructIPv4UDPPacket(src, dst, data) 68 } 69 if src.Address.Family().IsIPv6() && dst.Address.Family().IsIPv6() { 70 return constructIPv6UDPPacket(src, dst, data) 71 } 72 return nil, newError("not supported") 73 } 74 75 func constructIPv4UDPPacket(src, dst net.Destination, data []byte) ([]byte, error) { 76 ipv4 := &layers.IPv4{ 77 Version: 4, 78 Protocol: layers.IPProtocolUDP, 79 SrcIP: src.Address.IP(), 80 DstIP: dst.Address.IP(), 81 TTL: 64, // set TTL to a reasonable non-zero value to allow non-local routing 82 } 83 udp := &layers.UDP{ 84 SrcPort: layers.UDPPort(src.Port), 85 DstPort: layers.UDPPort(dst.Port), 86 } 87 err := udp.SetNetworkLayerForChecksum(ipv4) 88 if err != nil { 89 return nil, err 90 } 91 buffer := gopacket.NewSerializeBuffer() 92 if err := gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{ 93 FixLengths: true, 94 ComputeChecksums: true, 95 }, ipv4, udp, gopacket.Payload(data)); err != nil { 96 return nil, err 97 } 98 return buffer.Bytes(), nil 99 } 100 101 func constructIPv6UDPPacket(src, dst net.Destination, data []byte) ([]byte, error) { 102 ipv6 := &layers.IPv6{ 103 Version: 6, 104 NextHeader: layers.IPProtocolUDP, 105 SrcIP: src.Address.IP(), 106 DstIP: dst.Address.IP(), 107 HopLimit: 64, 108 } 109 udp := &layers.UDP{ 110 SrcPort: layers.UDPPort(src.Port), 111 DstPort: layers.UDPPort(dst.Port), 112 } 113 err := udp.SetNetworkLayerForChecksum(ipv6) 114 if err != nil { 115 return nil, err 116 } 117 buffer := gopacket.NewSerializeBuffer() 118 if err := gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{ 119 FixLengths: true, 120 ComputeChecksums: true, 121 }, ipv6, udp, gopacket.Payload(data)); err != nil { 122 return nil, err 123 } 124 return buffer.Bytes(), nil 125 }