udp.go 3.5 KB

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