packetman.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  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. /*
  20. Package packetman implements low-level manipulation of TCP packets, enabling a
  21. variety of strategies to evade network censorship.
  22. This implementation is entirely based on and is a subset of Geneva:
  23. Come as You Are: Helping Unmodified Clients Bypass Censorship with
  24. Server-side Evasion
  25. Kevin Bock, George Hughey, Louis-Henri Merino, Tania Arya, Daniel Liscinsky,
  26. Regina Pogosian, Dave Levin
  27. ACM SIGCOMM 2020
  28. Geneva: Evolving Censorship Evasion Strategies
  29. Kevin Bock, George Hughey, Xiao Qiang, Dave Levin
  30. ACM CCS 2019 (Conference on Computer and Communications Security)
  31. https://github.com/Kkevsterrr/geneva
  32. This package implements the equivilent of the Geneva "engine", which can
  33. execute packet manipulation strategies. It does not implement the genetic
  34. algorithm component.
  35. Other notable differences:
  36. - We intercept, parse, and transform only server-side outbound SYN-ACK
  37. packets. Geneva supports client-side packet manipulation with a more diverse
  38. set of trigger packets, but in practise we cannot execute most low-level
  39. packet operations on client platforms such as Android and iOS.
  40. - For expediancy, we use a simplified strategy syntax (called transformation
  41. specs, to avoid confusion with the more general original). As we do not
  42. evolve strategies, we do not use a tree representation and some
  43. randomization tranformations are simplified.
  44. At this time, full functionality is limited to the Linux platform.
  45. Security: external parties can induce the server to emit a SYN-ACK, invoking
  46. the packet manipulation logic. External parties cannot set the transformation
  47. specs, and, as the input is the server-side generated SYN-ACK packet, cannot
  48. influence the packet manipulation with any external input parameters.
  49. */
  50. package packetman
  51. import (
  52. "encoding/binary"
  53. "encoding/hex"
  54. "fmt"
  55. "net"
  56. "strings"
  57. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  58. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  59. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  60. "github.com/google/gopacket"
  61. "github.com/google/gopacket/layers"
  62. )
  63. // Config specifies a packet manipulation configuration.
  64. type Config struct {
  65. // Logger is used for logging events and metrics.
  66. Logger common.Logger
  67. // ProtocolPorts specifies the set of TCP ports to which SYN-ACK packet
  68. // interception and manipulation is to be applied. To accommodate hosts with
  69. // multiple IP addresses, packet interception is applied to all interfaces.
  70. ProtocolPorts []int
  71. // On Linux, which uses NFQUEUE and raw sockets, QueueNumber is the NFQUEUE
  72. // queue-num parameter to be used.
  73. QueueNumber int
  74. // On Linux, which uses NFQUEUE and raw sockets, SocketMark is the SO_MARK
  75. // value to be used. When 0, a default value is used.
  76. SocketMark int
  77. // Specs is the list of packet transformation Spec value that are to be
  78. // available for packet manipulation. Spec names must be unique.
  79. Specs []*Spec
  80. // SelectSpecName is a callback invoked for each intercepted SYN-ACK packet.
  81. // SelectSpecName must return a name of a Spec, in Specs, to apply that
  82. // transformation spec, or "" to send the SYN-ACK packet unmodified.
  83. // The second return value is arbitrary extra data that is associated
  84. // with the packet's connection; see GetAppliedSpecName.
  85. //
  86. // The inputs protocolPort and clientIP allow the callback to select a Spec
  87. // based on the protocol running at the intercepted packet's port and/or
  88. // client GeoIP.
  89. SelectSpecName func(protocolPort int, clientIP net.IP) (string, interface{})
  90. // SudoNetworkConfigCommands specifies whether to use "sudo" when executing
  91. // network configuration commands. See comment for same parameter in
  92. // psiphon/common/tun.
  93. SudoNetworkConfigCommands bool
  94. // AllowNoIPv6NetworkConfiguration indicates that failures while configuring
  95. // tun interfaces and routing for IPv6 are to be logged as warnings only. See
  96. // comment for same parameter in psiphon/common/tun.
  97. AllowNoIPv6NetworkConfiguration bool
  98. }
  99. // Spec specifies a set of transformations to be applied to an intercepted
  100. // SYN-ACK packet to produce zero or more replacement packets to be sent in
  101. // its place.
  102. //
  103. // Each element in PacketSpecs specifies a new outgoing packet. Each element
  104. // in a packet specification specifies an individual transformation to be
  105. // applied, in turn, to a copy of the intercepted SYN-ACK packet, producing
  106. // the outgoing packet.
  107. //
  108. // Syntax of individual tranformations:
  109. //
  110. // "TCP-flags random|<flags>"
  111. // flags: FSRPAUECN
  112. //
  113. // "TCP-<field> random|<hex>"
  114. // field: srcport, dstport, seq, ack, dataoffset, window, checksum, urgent
  115. //
  116. // "TCP-option-<option> random|omit|<hex>"
  117. // option: eol, nop, mss, windowscale, sackpermitted, sack, timestamps,
  118. // altchecksum, altchecksumdata, md5header, usertimeout
  119. //
  120. // "TCP-payload random|<hex>"
  121. //
  122. // For example, this Geneva strategy:
  123. //
  124. // [TCP:flags:SA]-duplicate(tamper{TCP:flags:replace:R},tamper{TCP:flags:replace:S})-| \/
  125. //
  126. // is represented as follows (in JSON encoding):
  127. //
  128. // [["TCP-flags R"], ["TCP-flags S"]]
  129. //
  130. // Field and option values must be the expected length (see implementation).
  131. //
  132. // A Spec may produce invalid packets. For example, the total options length
  133. // can exceed 40 bytes and the DataOffset field may overflow.
  134. type Spec struct {
  135. Name string
  136. PacketSpecs [][]string
  137. }
  138. // Validate checks that the transformation spec is syntactically correct.
  139. func (s *Spec) Validate() error {
  140. _, err := compileSpec(s)
  141. return errors.Trace(err)
  142. }
  143. type compiledSpec struct {
  144. name string
  145. compiledPacketSpecs [][]transformation
  146. }
  147. func compileSpec(spec *Spec) (*compiledSpec, error) {
  148. compiledPacketSpecs := make([][]transformation, len(spec.PacketSpecs))
  149. for i := range spec.PacketSpecs {
  150. compiledPacketSpecs[i] = make([]transformation, len(spec.PacketSpecs[i]))
  151. for j, transformationSpec := range spec.PacketSpecs[i] {
  152. transform, err := compileTransformation(transformationSpec)
  153. if err != nil {
  154. return nil, errors.Trace(err)
  155. }
  156. compiledPacketSpecs[i][j] = transform
  157. }
  158. }
  159. return &compiledSpec{
  160. name: spec.Name,
  161. compiledPacketSpecs: compiledPacketSpecs}, nil
  162. }
  163. func (spec *compiledSpec) apply(interceptedPacket gopacket.Packet) ([][]byte, error) {
  164. packets := make([][]byte, len(spec.compiledPacketSpecs))
  165. for i, packetTransformations := range spec.compiledPacketSpecs {
  166. var networkLayer gopacket.NetworkLayer
  167. var serializableNetworkLayer gopacket.SerializableLayer
  168. // Copy the network layer (IPv4 or IPv6) as modifications may be made to
  169. // checksums or lengths in that layer. Note this is not a deep copy of
  170. // fields such as the Options slice, as these are not modified.
  171. interceptedIPv4Layer := interceptedPacket.Layer(layers.LayerTypeIPv4)
  172. if interceptedIPv4Layer != nil {
  173. transformedIPv4 := *interceptedIPv4Layer.(*layers.IPv4)
  174. networkLayer = &transformedIPv4
  175. serializableNetworkLayer = &transformedIPv4
  176. } else {
  177. interceptedIPv6Layer := interceptedPacket.Layer(layers.LayerTypeIPv6)
  178. transformedIPv6 := *interceptedIPv6Layer.(*layers.IPv6)
  179. networkLayer = &transformedIPv6
  180. serializableNetworkLayer = &transformedIPv6
  181. }
  182. interceptedTCP := interceptedPacket.Layer(layers.LayerTypeTCP).(*layers.TCP)
  183. // Copy the TCP layer before transforming it. Again this is not a deep copy.
  184. // If a transformation modifies the Options slice, it will be copied at that
  185. // time.
  186. transformedTCP := *interceptedTCP
  187. var payload gopacket.Payload
  188. setCalculatedField := false
  189. fixLengths := true
  190. computeChecksums := true
  191. for _, transform := range packetTransformations {
  192. transform.apply(&transformedTCP, &payload)
  193. if t, ok := transform.(*transformationTCPField); ok && t.fieldName == tcpFieldDataOffset {
  194. fixLengths = false
  195. setCalculatedField = true
  196. }
  197. if t, ok := transform.(*transformationTCPField); ok && t.fieldName == tcpFieldChecksum {
  198. computeChecksums = false
  199. setCalculatedField = true
  200. }
  201. }
  202. err := transformedTCP.SetNetworkLayerForChecksum(networkLayer)
  203. if err != nil {
  204. return nil, errors.Trace(err)
  205. }
  206. buffer := gopacket.NewSerializeBuffer()
  207. options := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
  208. //warning: first SerializeLayers call may modify transformedTCP, we must copy the TCP DataOffset and Checksum
  209. tmpDataOffset := transformedTCP.DataOffset
  210. tmpChecksum := transformedTCP.Checksum
  211. err = gopacket.SerializeLayers(
  212. buffer,
  213. options,
  214. serializableNetworkLayer,
  215. &transformedTCP,
  216. payload)
  217. if err != nil {
  218. return nil, errors.Trace(err)
  219. }
  220. // In the first SerializeLayers call, all IP and TCP length and checksums
  221. // are recalculated and set to the correct values with transformations
  222. // applied.
  223. //
  224. // If the spec calls for setting the TCP DataOffset or Checksum, a second
  225. // SerializeLayers call is performed, which will repave these values without
  226. // recalculation; all other calculated lengths and checksums are retained
  227. // from the first round.
  228. if setCalculatedField {
  229. transformedTCP.DataOffset = tmpDataOffset
  230. transformedTCP.Checksum = tmpChecksum
  231. err = buffer.Clear()
  232. if err != nil {
  233. return nil, errors.Trace(err)
  234. }
  235. err = gopacket.SerializeLayers(
  236. buffer,
  237. gopacket.SerializeOptions{FixLengths: fixLengths, ComputeChecksums: computeChecksums},
  238. serializableNetworkLayer,
  239. &transformedTCP,
  240. payload)
  241. if err != nil {
  242. return nil, errors.Trace(err)
  243. }
  244. }
  245. packets[i] = buffer.Bytes()
  246. }
  247. return packets, nil
  248. }
  249. type transformation interface {
  250. apply(tcp *layers.TCP, payload *gopacket.Payload)
  251. }
  252. const (
  253. transformationTypeUnknown = iota
  254. transformationTypeOmit
  255. transformationTypeRandom
  256. transformationTypeValue
  257. )
  258. func compileTransformation(spec string) (transformation, error) {
  259. parts := strings.Split(spec, " ")
  260. if len(parts) != 2 {
  261. return nil, errors.Tracef("invalid spec: %s", spec)
  262. }
  263. fieldSpec := parts[0]
  264. valueSpec := parts[1]
  265. parts = strings.Split(fieldSpec, "-")
  266. if (len(parts) != 2 && len(parts) != 3) || parts[0] != "TCP" {
  267. return nil, errors.Tracef("invalid field spec: %s", fieldSpec)
  268. }
  269. var transformationType int
  270. if valueSpec == "omit" {
  271. transformationType = transformationTypeOmit
  272. } else if valueSpec == "random" {
  273. transformationType = transformationTypeRandom
  274. } else {
  275. transformationType = transformationTypeValue
  276. }
  277. var t transformation
  278. var err error
  279. if len(parts) == 3 {
  280. if parts[1] != "option" {
  281. return nil, errors.Tracef("invalid field spec: %s", fieldSpec)
  282. }
  283. t, err = newTransformationTCPOption(parts[2], transformationType, valueSpec)
  284. } else if parts[1] == "flags" {
  285. t, err = newTransformationTCPFlags(transformationType, valueSpec)
  286. } else if parts[1] == "payload" {
  287. t, err = newTransformationTCPPayload(transformationType, valueSpec)
  288. } else {
  289. t, err = newTransformationTCPField(parts[1], transformationType, valueSpec)
  290. }
  291. if err != nil {
  292. return nil, errors.Tracef("invalid field spec: %s: %v", fieldSpec, err)
  293. }
  294. return t, nil
  295. }
  296. type transformationTCPFlags struct {
  297. transformationType int
  298. flags string
  299. }
  300. func newTransformationTCPFlags(
  301. transformationType int, valueSpec string) (*transformationTCPFlags, error) {
  302. var flags string
  303. switch transformationType {
  304. case transformationTypeRandom:
  305. case transformationTypeValue:
  306. checkFlags := valueSpec
  307. for _, f := range "FSRPAUECN" {
  308. checkFlags = strings.ReplaceAll(checkFlags, string(f), "")
  309. }
  310. if checkFlags != "" {
  311. return nil, errors.Tracef("invalid value spec: %s", valueSpec)
  312. }
  313. flags = valueSpec
  314. default:
  315. return nil, errors.Tracef("invalid transformation type")
  316. }
  317. return &transformationTCPFlags{
  318. transformationType: transformationType,
  319. flags: flags,
  320. }, nil
  321. }
  322. func (t *transformationTCPFlags) apply(tcp *layers.TCP, _ *gopacket.Payload) {
  323. var flags string
  324. if t.transformationType == transformationTypeRandom {
  325. // Differs from Geneva, which often selects real flag combinations,
  326. // presumably to focus its search space:
  327. // https://github.com/Kkevsterrr/geneva/blob/de6823ba7723582054d2047083262cabffa85f36/layers/tcp_layer.py#L117-L121.
  328. for _, f := range "FSRPAUECN" {
  329. if prng.FlipCoin() {
  330. flags += string(f)
  331. }
  332. }
  333. } else {
  334. flags = t.flags
  335. }
  336. tcp.FIN = strings.Contains(flags, "F")
  337. tcp.SYN = strings.Contains(flags, "S")
  338. tcp.RST = strings.Contains(flags, "R")
  339. tcp.PSH = strings.Contains(flags, "P")
  340. tcp.ACK = strings.Contains(flags, "A")
  341. tcp.URG = strings.Contains(flags, "U")
  342. tcp.ECE = strings.Contains(flags, "E")
  343. tcp.CWR = strings.Contains(flags, "C")
  344. tcp.NS = strings.Contains(flags, "N")
  345. }
  346. type transformationTCPField struct {
  347. fieldName string
  348. transformationType int
  349. value []byte
  350. }
  351. const (
  352. tcpFieldSrcPort = "srcport"
  353. tcpFieldDstPort = "dstport"
  354. tcpFieldSeq = "seq"
  355. tcpFieldAck = "ack"
  356. tcpFieldDataOffset = "dataoffset"
  357. tcpFieldWindow = "window"
  358. tcpFieldChecksum = "checksum"
  359. tcpFieldUrgent = "urgent"
  360. )
  361. func newTransformationTCPField(
  362. fieldName string, transformationType int, valueSpec string) (*transformationTCPField, error) {
  363. length := 0
  364. switch fieldName {
  365. case tcpFieldSrcPort:
  366. length = 2
  367. case tcpFieldDstPort:
  368. length = 2
  369. case tcpFieldSeq:
  370. length = 4
  371. case tcpFieldAck:
  372. length = 4
  373. case tcpFieldDataOffset:
  374. length = 1
  375. case tcpFieldWindow:
  376. length = 2
  377. case tcpFieldChecksum:
  378. length = 2
  379. case tcpFieldUrgent:
  380. length = 2
  381. default:
  382. return nil, errors.Tracef("invalid field name: %s", fieldName)
  383. }
  384. var decodedValue []byte
  385. switch transformationType {
  386. case transformationTypeRandom:
  387. case transformationTypeValue:
  388. var err error
  389. decodedValue, err = hex.DecodeString(valueSpec)
  390. if err == nil && len(decodedValue) != length {
  391. err = fmt.Errorf("invalid value length: %d", len(decodedValue))
  392. }
  393. if err != nil {
  394. return nil, errors.Tracef("invalid value spec: %s: %v", valueSpec, err)
  395. }
  396. default:
  397. return nil, errors.Tracef("invalid transformation type")
  398. }
  399. return &transformationTCPField{
  400. fieldName: fieldName,
  401. transformationType: transformationType,
  402. value: decodedValue,
  403. }, nil
  404. }
  405. func (t *transformationTCPField) apply(tcp *layers.TCP, _ *gopacket.Payload) {
  406. var value [4]byte
  407. if t.transformationType == transformationTypeRandom {
  408. _, _ = prng.Read(value[:])
  409. } else {
  410. copy(value[:], t.value)
  411. }
  412. switch t.fieldName {
  413. case tcpFieldSrcPort:
  414. tcp.SrcPort = layers.TCPPort(binary.BigEndian.Uint16(value[:]))
  415. case tcpFieldDstPort:
  416. tcp.DstPort = layers.TCPPort(binary.BigEndian.Uint16(value[:]))
  417. case tcpFieldSeq:
  418. tcp.Seq = binary.BigEndian.Uint32(value[:])
  419. case tcpFieldAck:
  420. tcp.Ack = binary.BigEndian.Uint32(value[:])
  421. case tcpFieldDataOffset:
  422. tcp.DataOffset = value[0]
  423. // DataOffset is a 4-bit field; the most significant 4 bits are ignored
  424. tcp.DataOffset &= 0x0f
  425. case tcpFieldWindow:
  426. // Differs from Geneva: https://github.com/Kkevsterrr/geneva/blob/de6823ba7723582054d2047083262cabffa85f36/layers/tcp_layer.py#L117-L121
  427. tcp.Window = binary.BigEndian.Uint16(value[:])
  428. case tcpFieldChecksum:
  429. tcp.Checksum = binary.BigEndian.Uint16(value[:])
  430. case tcpFieldUrgent:
  431. tcp.Urgent = binary.BigEndian.Uint16(value[:])
  432. }
  433. }
  434. type transformationTCPOption struct {
  435. optionName string
  436. transformationType int
  437. value []byte
  438. }
  439. const (
  440. tcpOptionEOL = "eol"
  441. tcpOptionNOP = "nop"
  442. tcpOptionMSS = "mss"
  443. tcpOptionWindowScale = "windowscale"
  444. tcpOptionSACKPermitted = "sackpermitted"
  445. tcpOptionSACK = "sack"
  446. tcpOptionTimestamps = "timestamps"
  447. tcpOptionAltChecksum = "altchecksum"
  448. tcpOptionAltChecksumData = "altchecksumdata"
  449. tcpOptionMD5Header = "md5header"
  450. tcpOptionUserTimeout = "usertimeout"
  451. )
  452. func tcpOptionInfo(optionName string) (layers.TCPOptionKind, []int, bool) {
  453. var kind layers.TCPOptionKind
  454. var validLengths []int
  455. switch optionName {
  456. case tcpOptionEOL:
  457. kind = layers.TCPOptionKindEndList
  458. validLengths = nil // no option length field
  459. case tcpOptionNOP:
  460. kind = layers.TCPOptionKindNop
  461. validLengths = nil
  462. case tcpOptionMSS:
  463. kind = layers.TCPOptionKindMSS
  464. validLengths = []int{2}
  465. case tcpOptionWindowScale:
  466. kind = layers.TCPOptionKindWindowScale
  467. validLengths = []int{1}
  468. case tcpOptionSACKPermitted:
  469. kind = layers.TCPOptionKindSACKPermitted
  470. validLengths = []int{0}
  471. case tcpOptionSACK:
  472. // https://tools.ietf.org/html/rfc2018
  473. kind = layers.TCPOptionKindSACK
  474. validLengths = []int{8, 16, 24, 32}
  475. case tcpOptionTimestamps:
  476. kind = layers.TCPOptionKindTimestamps
  477. validLengths = []int{8}
  478. case tcpOptionAltChecksum:
  479. kind = layers.TCPOptionKindAltChecksum
  480. validLengths = []int{1}
  481. case tcpOptionAltChecksumData:
  482. // https://tools.ietf.org/html/rfc1145:
  483. // "this field is used only when the alternate checksum that is negotiated is longer than 16 bits"
  484. //
  485. // Geneva allows setting length 0.
  486. kind = layers.TCPOptionKindAltChecksumData
  487. validLengths = []int{0, 4}
  488. case tcpOptionMD5Header:
  489. // https://tools.ietf.org/html/rfc2385
  490. kind = layers.TCPOptionKind(19)
  491. validLengths = []int{16}
  492. case tcpOptionUserTimeout:
  493. // https://tools.ietf.org/html/rfc5482
  494. kind = layers.TCPOptionKind(28)
  495. validLengths = []int{2}
  496. default:
  497. return kind, nil, false
  498. }
  499. return kind, validLengths, true
  500. }
  501. func newTransformationTCPOption(
  502. optionName string, transformationType int, valueSpec string) (*transformationTCPOption, error) {
  503. _, validLengths, ok := tcpOptionInfo(optionName)
  504. if !ok {
  505. return nil, errors.Tracef("invalid option name: %s", optionName)
  506. }
  507. var decodedValue []byte
  508. switch transformationType {
  509. case transformationTypeOmit:
  510. case transformationTypeRandom:
  511. case transformationTypeValue:
  512. var err error
  513. decodedValue, err = hex.DecodeString(valueSpec)
  514. if err == nil {
  515. if validLengths == nil {
  516. validLengths = []int{0}
  517. }
  518. if !common.ContainsInt(validLengths, len(decodedValue)) {
  519. err = fmt.Errorf("invalid value length: %d", len(decodedValue))
  520. }
  521. }
  522. if err != nil {
  523. return nil, errors.Tracef("invalid value spec: %s: %v", valueSpec, err)
  524. }
  525. default:
  526. return nil, errors.Tracef("invalid transformation type")
  527. }
  528. return &transformationTCPOption{
  529. optionName: optionName,
  530. transformationType: transformationType,
  531. value: decodedValue,
  532. }, nil
  533. }
  534. func (t *transformationTCPOption) apply(tcp *layers.TCP, _ *gopacket.Payload) {
  535. // This transformation makes a copy of all existing TCPOption structs, so
  536. // transformed option slices are not shared between multiple packets.
  537. //
  538. // All existing options are retained in the existing order. Modified options
  539. // are overwritten in place. New options are appended to the end of the
  540. // option list.
  541. //
  542. // Total option set size is not tracked or validated and the DataOffset TCP
  543. // field can overflow.
  544. //
  545. // Limitations:
  546. // - Inserting an option at a specific position is not supported.
  547. // - OptionLengths cannot be set to arbitrary values.
  548. // - Each option transformation executes a full copy of the existing option
  549. // list, which is not efficient for a long list of option transformations.
  550. kind, validLengths, _ := tcpOptionInfo(t.optionName)
  551. var options []layers.TCPOption
  552. // The for loop iterates over all existing options plus one additional
  553. // iteration, copying or modifying existing options and then appending a new
  554. // option if required. This flag ensures that we don't both modify and append
  555. // a new option.
  556. applied := false
  557. for i := 0; i <= len(tcp.Options); i++ {
  558. if i < len(tcp.Options) {
  559. option := tcp.Options[i]
  560. if option.OptionType != kind {
  561. options = append(options, layers.TCPOption{
  562. OptionType: option.OptionType,
  563. OptionLength: option.OptionLength,
  564. OptionData: append([]byte(nil), option.OptionData...),
  565. })
  566. continue
  567. }
  568. } else if applied {
  569. // Skip the append iteration if we already applied the transformation to an
  570. // existing option.
  571. continue
  572. }
  573. // TCP options with validLengths == nil have only the "kind" byte and total
  574. // length 1. Options with validLengths have the "kind" byte, the "length"
  575. // byte, and 0 or more data bytes; in this case, "length" is 2 + the length
  576. // of the data.
  577. switch t.transformationType {
  578. case transformationTypeOmit:
  579. continue
  580. case transformationTypeRandom:
  581. if validLengths == nil {
  582. options = append(options, layers.TCPOption{
  583. OptionType: kind,
  584. OptionLength: 1,
  585. })
  586. } else {
  587. length := validLengths[prng.Range(0, len(validLengths)-1)]
  588. var data []byte
  589. if length > 0 {
  590. data = prng.Bytes(length)
  591. }
  592. options = append(options, layers.TCPOption{
  593. OptionType: kind,
  594. OptionLength: 2 + uint8(length),
  595. OptionData: data,
  596. })
  597. }
  598. applied = true
  599. case transformationTypeValue:
  600. if validLengths == nil {
  601. options = append(options, layers.TCPOption{
  602. OptionType: kind,
  603. OptionLength: 1,
  604. })
  605. } else {
  606. length := len(t.value)
  607. var data []byte
  608. if length > 0 {
  609. data = append([]byte(nil), t.value...)
  610. }
  611. options = append(options, layers.TCPOption{
  612. OptionType: kind,
  613. OptionLength: 2 + uint8(length),
  614. OptionData: data,
  615. })
  616. }
  617. applied = true
  618. }
  619. }
  620. tcp.Options = options
  621. }
  622. type transformationTCPPayload struct {
  623. transformationType int
  624. value []byte
  625. }
  626. func newTransformationTCPPayload(
  627. transformationType int, valueSpec string) (*transformationTCPPayload, error) {
  628. var decodedValue []byte
  629. switch transformationType {
  630. case transformationTypeOmit:
  631. case transformationTypeRandom:
  632. case transformationTypeValue:
  633. var err error
  634. decodedValue, err = hex.DecodeString(valueSpec)
  635. if err != nil {
  636. return nil, errors.Tracef("invalid value spec: %s: %v", valueSpec, err)
  637. }
  638. default:
  639. return nil, errors.Tracef("invalid transformation type")
  640. }
  641. return &transformationTCPPayload{
  642. transformationType: transformationType,
  643. value: decodedValue,
  644. }, nil
  645. }
  646. func (t *transformationTCPPayload) apply(tcp *layers.TCP, payload *gopacket.Payload) {
  647. var value []byte
  648. switch t.transformationType {
  649. case transformationTypeOmit:
  650. case transformationTypeRandom:
  651. // Differs from Geneva: https://github.com/Kkevsterrr/geneva/blob/de6823ba7723582054d2047083262cabffa85f36/layers/layer.py#L191-L197
  652. value = prng.Bytes(prng.Range(1, 200))
  653. case transformationTypeValue:
  654. value = t.value
  655. }
  656. if value == nil {
  657. // Omit the payload.
  658. *payload = nil
  659. } else {
  660. // Change the payload.
  661. *payload = append([]byte(nil), value...)
  662. }
  663. }
  664. func stripEOLOption(packet gopacket.Packet) {
  665. // gopacket.NewPacket appears to decode padding (0s) as an explicit EOL
  666. // option (value 0) at the end of the option list. This helper strips that
  667. // option, allowing append-option transformations to work as expected.
  668. // gopacket TCP serialization will re-add padding as required.
  669. tcpLayer := packet.Layer(layers.LayerTypeTCP).(*layers.TCP)
  670. if len(tcpLayer.Options) > 0 &&
  671. tcpLayer.Options[len(tcpLayer.Options)-1].OptionType == layers.TCPOptionKindEndList {
  672. tcpLayer.Options = tcpLayer.Options[:len(tcpLayer.Options)-1]
  673. }
  674. }