packetman_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Copyright (c) 2020, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package packetman
  20. import (
  21. "bytes"
  22. "encoding/json"
  23. "net"
  24. "testing"
  25. "github.com/google/gopacket"
  26. "github.com/google/gopacket/layers"
  27. )
  28. func TestTransformations(t *testing.T) {
  29. // Test: apply various transformations to an original packet, then parse the
  30. // resulting packets and check that flags/fields/options are as expected.
  31. // Limitation: gopacket, used here in the test to verify transformations,
  32. // will fail to parse some or all of certain packets that can be created by
  33. // certain transformations. gopacket will fail to parse packets with too many
  34. // option bytes or invalid DataOffset values. gopacket will stop
  35. // deserializing TCP options as soon as it encounters the EOL option, even if
  36. // the packet actually contains more options. Etc.
  37. specJSON := []byte(`
  38. {
  39. "Name": "test-spec",
  40. "PacketSpecs": [
  41. ["TCP-flags SA",
  42. "TCP-flags S",
  43. "TCP-srcport ffff",
  44. "TCP-dstport ffff",
  45. "TCP-seq ffffffff",
  46. "TCP-ack ffffffff",
  47. "TCP-dataoffset 0f",
  48. "TCP-window ffff",
  49. "TCP-checksum ffff",
  50. "TCP-urgent ffff",
  51. "TCP-option-nop omit",
  52. "TCP-option-mss ffff",
  53. "TCP-option-windowscale ff",
  54. "TCP-option-sackpermitted ",
  55. "TCP-option-sack ffffffffffffffff",
  56. "TCP-option-timestamps ffffffffffffffff",
  57. "TCP-payload eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
  58. "TCP-payload ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"],
  59. ["TCP-flags random",
  60. "TCP-srcport random",
  61. "TCP-dstport random",
  62. "TCP-seq random",
  63. "TCP-ack random",
  64. "TCP-dataoffset random",
  65. "TCP-window random",
  66. "TCP-checksum random",
  67. "TCP-urgent random",
  68. "TCP-option-mss random",
  69. "TCP-option-windowscale random",
  70. "TCP-option-sackpermitted random",
  71. "TCP-option-timestamps random",
  72. "TCP-payload random"]
  73. ]
  74. }
  75. `)
  76. var spec *Spec
  77. err := json.Unmarshal(specJSON, &spec)
  78. if err != nil {
  79. t.Fatalf("json.Unmarshal failed: %v", err)
  80. }
  81. c, err := compileSpec(spec)
  82. if err != nil {
  83. t.Fatalf("compileSpec failed: %v", err)
  84. }
  85. if c.name != spec.Name {
  86. t.Fatalf("unexpected compiled spec name: %s", c.name)
  87. }
  88. originalIPv4 := &layers.IPv4{
  89. Version: 0x04,
  90. IHL: 0x05,
  91. Protocol: 0x06,
  92. SrcIP: net.IPv4(192, 168, 0, 1),
  93. DstIP: net.IPv4(192, 168, 0, 2),
  94. }
  95. originalTCP := &layers.TCP{
  96. SYN: true,
  97. ACK: true,
  98. Options: []layers.TCPOption{
  99. layers.TCPOption{OptionType: layers.TCPOptionKindNop, OptionLength: 1},
  100. layers.TCPOption{OptionType: layers.TCPOptionKindSACKPermitted, OptionLength: 2},
  101. layers.TCPOption{OptionType: layers.TCPOptionKindSACK, OptionLength: 10, OptionData: bytes.Repeat([]byte{0}, 8)},
  102. layers.TCPOption{OptionType: layers.TCPOptionKindTimestamps, OptionLength: 10, OptionData: bytes.Repeat([]byte{0}, 8)},
  103. },
  104. }
  105. originalTCP.SetNetworkLayerForChecksum(originalIPv4)
  106. originalPayload := gopacket.Payload([]byte{0, 0, 0, 0})
  107. buffer := gopacket.NewSerializeBuffer()
  108. gopacket.SerializeLayers(
  109. buffer,
  110. gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true},
  111. originalIPv4,
  112. originalTCP,
  113. originalPayload)
  114. originalPacketData := buffer.Bytes()
  115. originalPacket := gopacket.NewPacket(originalPacketData, layers.LayerTypeIPv4, gopacket.Default)
  116. errLayer := originalPacket.ErrorLayer()
  117. if errLayer != nil {
  118. t.Fatalf("gopacket.NewPacket failed: %v", errLayer.Error())
  119. }
  120. stripEOLOption(originalPacket)
  121. repeats := 1000
  122. repeatLoop:
  123. for i := 0; i < repeats; i++ {
  124. lastRepeat := i == repeats-1
  125. injectPackets, err := c.apply(originalPacket)
  126. if err != nil {
  127. t.Fatalf("apply failed: %v", err)
  128. }
  129. if len(injectPackets) != 2 {
  130. t.Fatalf("unexpected injectPackets count: %d", len(injectPackets))
  131. }
  132. for packetNum, packetData := range injectPackets {
  133. packet := gopacket.NewPacket(packetData, layers.LayerTypeIPv4, gopacket.Default)
  134. errLayer := packet.ErrorLayer()
  135. if errLayer != nil {
  136. t.Fatalf("gopacket.NewPacket failed: %v", errLayer.Error())
  137. }
  138. tcpLayer := packet.Layer(layers.LayerTypeTCP)
  139. if tcpLayer == nil {
  140. t.Fatalf("missing TCP layer")
  141. }
  142. tcp := tcpLayer.(*layers.TCP)
  143. payloadLayer := packet.Layer(gopacket.LayerTypePayload)
  144. if payloadLayer == nil {
  145. t.Fatalf("missing payload layer")
  146. }
  147. payload := payloadLayer.(*gopacket.Payload)
  148. optionsEqual := func(a, b layers.TCPOption) bool {
  149. if a.OptionType != b.OptionType ||
  150. a.OptionLength != b.OptionLength ||
  151. !bytes.Equal(a.OptionData, b.OptionData) {
  152. return false
  153. }
  154. return true
  155. }
  156. optionsListEqual := func(a, b []layers.TCPOption) bool {
  157. if len(a) != len(b) {
  158. return false
  159. }
  160. for i, o := range a {
  161. if !optionsEqual(o, b[i]) {
  162. return false
  163. }
  164. }
  165. return true
  166. }
  167. if packetNum == 0 {
  168. // With multiple, redundant value specs (TCP-flags in the test case) the
  169. // _last_ value spec should be applied. Values should be truncated to
  170. // protocol lengths. The NOP option in the original packet should be
  171. // omitted.
  172. expectedOptions := []layers.TCPOption{
  173. layers.TCPOption{OptionType: layers.TCPOptionKindSACKPermitted, OptionLength: 2},
  174. layers.TCPOption{OptionType: layers.TCPOptionKindSACK, OptionLength: 10, OptionData: bytes.Repeat([]byte{0xff}, 8)},
  175. layers.TCPOption{OptionType: layers.TCPOptionKindTimestamps, OptionLength: 10, OptionData: bytes.Repeat([]byte{0xff}, 8)},
  176. layers.TCPOption{OptionType: layers.TCPOptionKindMSS, OptionLength: 4, OptionData: bytes.Repeat([]byte{0xff}, 2)},
  177. layers.TCPOption{OptionType: layers.TCPOptionKindWindowScale, OptionLength: 3, OptionData: bytes.Repeat([]byte{0xff}, 1)},
  178. layers.TCPOption{OptionType: layers.TCPOptionKindEndList, OptionLength: 1},
  179. }
  180. if tcp.SrcPort != 0xffff ||
  181. tcp.DstPort != 0xffff ||
  182. tcp.Seq != 0xffffffff ||
  183. tcp.Ack != 0xffffffff ||
  184. tcp.FIN || !tcp.SYN || tcp.RST || tcp.PSH || tcp.ACK ||
  185. tcp.URG || tcp.ECE || tcp.CWR || tcp.NS ||
  186. tcp.Window != 0xffff ||
  187. tcp.Urgent != 0xffff ||
  188. !optionsListEqual(tcp.Options, expectedOptions) {
  189. t.Fatalf("unexpected TCP layer: %+v", tcp)
  190. }
  191. expectedPayload := bytes.Repeat([]byte{0xff}, 32)
  192. if !bytes.Equal(expectedPayload, *payload) {
  193. t.Fatalf("unexpected payload: %x", *payload)
  194. }
  195. } else {
  196. // In at least one repeat, randomized fields fully differ from original,
  197. // including zero-values; original NOP and SACK options retained; random
  198. // options have correct protocol lengths.
  199. if tcp.SrcPort == originalTCP.SrcPort ||
  200. tcp.DstPort == originalTCP.DstPort ||
  201. tcp.Seq == originalTCP.Seq ||
  202. tcp.Ack == originalTCP.Ack ||
  203. (tcp.FIN == originalTCP.FIN &&
  204. tcp.SYN == originalTCP.SYN &&
  205. tcp.RST == originalTCP.RST &&
  206. tcp.PSH == originalTCP.PSH &&
  207. tcp.ACK == originalTCP.ACK &&
  208. tcp.URG == originalTCP.URG &&
  209. tcp.ECE == originalTCP.ECE &&
  210. tcp.CWR == originalTCP.CWR &&
  211. tcp.NS == originalTCP.NS) ||
  212. tcp.Window == originalTCP.Window ||
  213. tcp.Checksum == originalTCP.Checksum ||
  214. tcp.Urgent == originalTCP.Urgent ||
  215. len(tcp.Options) != 7 ||
  216. !optionsEqual(tcp.Options[0], originalTCP.Options[0]) ||
  217. !optionsEqual(tcp.Options[1], originalTCP.Options[1]) ||
  218. !optionsEqual(tcp.Options[2], originalTCP.Options[2]) ||
  219. tcp.Options[3].OptionType != layers.TCPOptionKindTimestamps ||
  220. tcp.Options[3].OptionLength != 10 ||
  221. optionsEqual(tcp.Options[3], originalTCP.Options[3]) ||
  222. tcp.Options[4].OptionType != layers.TCPOptionKindMSS ||
  223. tcp.Options[4].OptionLength != 4 ||
  224. tcp.Options[5].OptionType != layers.TCPOptionKindWindowScale ||
  225. tcp.Options[5].OptionLength != 3 ||
  226. tcp.Options[6].OptionType != layers.TCPOptionKindEndList ||
  227. bytes.Equal(originalPayload, *payload) {
  228. if lastRepeat {
  229. t.Fatalf("unexpected TCP layer: %+v", tcp)
  230. }
  231. } else {
  232. break repeatLoop
  233. }
  234. }
  235. }
  236. }
  237. }