packetman.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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|<base64>"
  114. // field: srcport, dstport, seq, ack, dataoffset, window, checksum, urgent
  115. //
  116. // "TCP-option-<option> random|omit|<base64>"
  117. // option: eol, nop, mss, windowscale, sackpermitted, sack, timestamps,
  118. // altchecksum, altchecksumdata, md5header, usertimeout
  119. //
  120. // "TCP-payload random|<base64>"
  121. //
  122. // For example, this Geneva strategy:
  123. // [TCP:flags:SA]-duplicate(tamper{TCP:flags:replace:R},tamper{TCP:flags:replace:S})-| \/
  124. //
  125. // is represented as follows (in JSON encoding):
  126. // [["TCP-flags R"], ["TCP-flags S"]]
  127. //
  128. //
  129. // Field and option values must be the expected length (see implementation).
  130. //
  131. // A Spec may produce invalid packets. For example, the total options length
  132. // can exceed 40 bytes and the DataOffset field may overflow.
  133. type Spec struct {
  134. Name string
  135. PacketSpecs [][]string
  136. }
  137. // Validate checks that the transformation spec is syntactically correct.
  138. func (s *Spec) Validate() error {
  139. _, err := compileSpec(s)
  140. return errors.Trace(err)
  141. }
  142. type compiledSpec struct {
  143. name string
  144. compiledPacketSpecs [][]transformation
  145. }
  146. func compileSpec(spec *Spec) (*compiledSpec, error) {
  147. compiledPacketSpecs := make([][]transformation, len(spec.PacketSpecs))
  148. for i, _ := range spec.PacketSpecs {
  149. compiledPacketSpecs[i] = make([]transformation, len(spec.PacketSpecs[i]))
  150. for j, transformationSpec := range spec.PacketSpecs[i] {
  151. transform, err := compileTransformation(transformationSpec)
  152. if err != nil {
  153. return nil, errors.Trace(err)
  154. }
  155. compiledPacketSpecs[i][j] = transform
  156. }
  157. }
  158. return &compiledSpec{
  159. name: spec.Name,
  160. compiledPacketSpecs: compiledPacketSpecs}, nil
  161. }
  162. func (spec *compiledSpec) apply(interceptedPacket gopacket.Packet) ([][]byte, error) {
  163. packets := make([][]byte, len(spec.compiledPacketSpecs))
  164. for i, packetTransformations := range spec.compiledPacketSpecs {
  165. var networkLayer gopacket.NetworkLayer
  166. var serializableNetworkLayer gopacket.SerializableLayer
  167. // Copy the network layer (IPv4 or IPv6) as modifications may be made to
  168. // checksums or lengths in that layer. Note this is not a deep copy of
  169. // fields such as the Options slice, as these are not modified.
  170. interceptedIPv4Layer := interceptedPacket.Layer(layers.LayerTypeIPv4)
  171. if interceptedIPv4Layer != nil {
  172. transformedIPv4 := *interceptedIPv4Layer.(*layers.IPv4)
  173. networkLayer = &transformedIPv4
  174. serializableNetworkLayer = &transformedIPv4
  175. } else {
  176. interceptedIPv6Layer := interceptedPacket.Layer(layers.LayerTypeIPv6)
  177. transformedIPv6 := *interceptedIPv6Layer.(*layers.IPv6)
  178. networkLayer = &transformedIPv6
  179. serializableNetworkLayer = &transformedIPv6
  180. }
  181. interceptedTCP := interceptedPacket.Layer(layers.LayerTypeTCP).(*layers.TCP)
  182. // Copy the TCP layer before transforming it. Again this is not a deep copy.
  183. // If a transformation modifies the Options slice, it will be copied at that
  184. // time.
  185. transformedTCP := *interceptedTCP
  186. var payload gopacket.Payload
  187. setCalculatedField := false
  188. for _, transform := range packetTransformations {
  189. transform.apply(&transformedTCP, &payload)
  190. if transform.setsCalculatedField() {
  191. setCalculatedField = true
  192. }
  193. }
  194. err := transformedTCP.SetNetworkLayerForChecksum(networkLayer)
  195. if err != nil {
  196. return nil, errors.Trace(err)
  197. }
  198. buffer := gopacket.NewSerializeBuffer()
  199. options := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
  200. gopacket.SerializeLayers(
  201. buffer,
  202. options,
  203. serializableNetworkLayer,
  204. &transformedTCP,
  205. payload)
  206. // In the first SerializeLayers call, all IP and TCP length and checksums
  207. // are recalculated and set to the correct values with transformations
  208. // applied.
  209. //
  210. // If the spec calls for setting the TCP DataOffset or Checksum, a second
  211. // SerializeLayers call is performed, which will repave these values without
  212. // recalculation; all other calculated lengths and checksums are retained
  213. // from the first round.
  214. if setCalculatedField {
  215. buffer.Clear()
  216. gopacket.SerializeLayers(
  217. buffer,
  218. gopacket.SerializeOptions{},
  219. serializableNetworkLayer,
  220. &transformedTCP,
  221. payload)
  222. }
  223. packets[i] = buffer.Bytes()
  224. }
  225. return packets, nil
  226. }
  227. type transformation interface {
  228. apply(tcp *layers.TCP, payload *gopacket.Payload)
  229. setsCalculatedField() bool
  230. }
  231. const (
  232. transformationTypeUnknown = iota
  233. transformationTypeOmit
  234. transformationTypeRandom
  235. transformationTypeValue
  236. )
  237. func compileTransformation(spec string) (transformation, error) {
  238. parts := strings.Split(spec, " ")
  239. if len(parts) != 2 {
  240. return nil, errors.Tracef("invalid spec: %s", spec)
  241. }
  242. fieldSpec := parts[0]
  243. valueSpec := parts[1]
  244. parts = strings.Split(fieldSpec, "-")
  245. if (len(parts) != 2 && len(parts) != 3) || parts[0] != "TCP" {
  246. return nil, errors.Tracef("invalid field spec: %s", fieldSpec)
  247. }
  248. var transformationType int
  249. if valueSpec == "omit" {
  250. transformationType = transformationTypeOmit
  251. } else if valueSpec == "random" {
  252. transformationType = transformationTypeRandom
  253. } else {
  254. transformationType = transformationTypeValue
  255. }
  256. var t transformation
  257. var err error
  258. if len(parts) == 3 {
  259. if parts[1] != "option" {
  260. return nil, errors.Tracef("invalid field spec: %s", fieldSpec)
  261. }
  262. t, err = newTransformationTCPOption(parts[2], transformationType, valueSpec)
  263. } else if parts[1] == "flags" {
  264. t, err = newTransformationTCPFlags(transformationType, valueSpec)
  265. } else if parts[1] == "payload" {
  266. t, err = newTransformationTCPPayload(transformationType, valueSpec)
  267. } else {
  268. t, err = newTransformationTCPField(parts[1], transformationType, valueSpec)
  269. }
  270. if err != nil {
  271. return nil, errors.Tracef("invalid field spec: %s: %v", fieldSpec, err)
  272. }
  273. return t, nil
  274. }
  275. type transformationTCPFlags struct {
  276. transformationType int
  277. flags string
  278. }
  279. func newTransformationTCPFlags(
  280. transformationType int, valueSpec string) (*transformationTCPFlags, error) {
  281. var flags string
  282. switch transformationType {
  283. case transformationTypeRandom:
  284. case transformationTypeValue:
  285. checkFlags := valueSpec
  286. for _, f := range "FSRPAUECN" {
  287. checkFlags = strings.ReplaceAll(checkFlags, string(f), "")
  288. }
  289. if checkFlags != "" {
  290. return nil, errors.Tracef("invalid value spec: %s", valueSpec)
  291. }
  292. flags = valueSpec
  293. default:
  294. return nil, errors.Tracef("invalid transformation type")
  295. }
  296. return &transformationTCPFlags{
  297. transformationType: transformationType,
  298. flags: flags,
  299. }, nil
  300. }
  301. func (t *transformationTCPFlags) apply(tcp *layers.TCP, _ *gopacket.Payload) {
  302. var flags string
  303. if t.transformationType == transformationTypeRandom {
  304. // Differs from Geneva, which often selects real flag combinations,
  305. // presumably to focus its search space:
  306. // https://github.com/Kkevsterrr/geneva/blob/de6823ba7723582054d2047083262cabffa85f36/layers/tcp_layer.py#L117-L121.
  307. for _, f := range "FSRPAUECN" {
  308. if prng.FlipCoin() {
  309. flags += string(f)
  310. }
  311. }
  312. } else {
  313. flags = t.flags
  314. }
  315. tcp.FIN = strings.Index(t.flags, "F") != -1
  316. tcp.SYN = strings.Index(t.flags, "S") != -1
  317. tcp.RST = strings.Index(t.flags, "R") != -1
  318. tcp.PSH = strings.Index(t.flags, "P") != -1
  319. tcp.ACK = strings.Index(t.flags, "A") != -1
  320. tcp.URG = strings.Index(t.flags, "U") != -1
  321. tcp.ECE = strings.Index(t.flags, "E") != -1
  322. tcp.CWR = strings.Index(t.flags, "C") != -1
  323. tcp.NS = strings.Index(t.flags, "N") != -1
  324. }
  325. func (t *transformationTCPFlags) setsCalculatedField() bool {
  326. return false
  327. }
  328. type transformationTCPField struct {
  329. fieldName string
  330. transformationType int
  331. value []byte
  332. }
  333. const (
  334. tcpFieldSrcPort = "srcport"
  335. tcpFieldDstPort = "dstport"
  336. tcpFieldSeq = "seq"
  337. tcpFieldAck = "ack"
  338. tcpFieldDataOffset = "dataoffset"
  339. tcpFieldWindow = "window"
  340. tcpFieldChecksum = "checksum"
  341. tcpFieldUrgent = "urgent"
  342. )
  343. func newTransformationTCPField(
  344. fieldName string, transformationType int, valueSpec string) (*transformationTCPField, error) {
  345. length := 0
  346. switch fieldName {
  347. case tcpFieldSrcPort:
  348. length = 2
  349. case tcpFieldDstPort:
  350. length = 2
  351. case tcpFieldSeq:
  352. length = 4
  353. case tcpFieldAck:
  354. length = 4
  355. case tcpFieldDataOffset:
  356. length = 1
  357. case tcpFieldWindow:
  358. length = 2
  359. case tcpFieldChecksum:
  360. length = 2
  361. case tcpFieldUrgent:
  362. length = 2
  363. default:
  364. return nil, errors.Tracef("invalid field name: %s", fieldName)
  365. }
  366. var decodedValue []byte
  367. switch transformationType {
  368. case transformationTypeRandom:
  369. case transformationTypeValue:
  370. var err error
  371. decodedValue, err = hex.DecodeString(valueSpec)
  372. if err == nil && len(decodedValue) != length {
  373. err = fmt.Errorf("invalid value length: %d", len(decodedValue))
  374. }
  375. if err != nil {
  376. return nil, errors.Tracef("invalid value spec: %s: %v", valueSpec, err)
  377. }
  378. default:
  379. return nil, errors.Tracef("invalid transformation type")
  380. }
  381. return &transformationTCPField{
  382. fieldName: fieldName,
  383. transformationType: transformationType,
  384. value: decodedValue,
  385. }, nil
  386. }
  387. func (t *transformationTCPField) apply(tcp *layers.TCP, _ *gopacket.Payload) {
  388. var value [4]byte
  389. if t.transformationType == transformationTypeRandom {
  390. _, _ = prng.Read(value[:])
  391. } else {
  392. copy(value[:], t.value)
  393. }
  394. switch t.fieldName {
  395. case tcpFieldSrcPort:
  396. tcp.SrcPort = layers.TCPPort(binary.BigEndian.Uint16(value[:]))
  397. case tcpFieldDstPort:
  398. tcp.DstPort = layers.TCPPort(binary.BigEndian.Uint16(value[:]))
  399. case tcpFieldSeq:
  400. tcp.Seq = binary.BigEndian.Uint32(value[:])
  401. case tcpFieldAck:
  402. tcp.Ack = binary.BigEndian.Uint32(value[:])
  403. case tcpFieldDataOffset:
  404. tcp.DataOffset = value[0]
  405. // DataOffset is a 4-bit field; the most significant 4 bits are ignored
  406. tcp.DataOffset &= 0x0f
  407. case tcpFieldWindow:
  408. // Differs from Geneva: https://github.com/Kkevsterrr/geneva/blob/de6823ba7723582054d2047083262cabffa85f36/layers/tcp_layer.py#L117-L121
  409. tcp.Window = binary.BigEndian.Uint16(value[:])
  410. case tcpFieldChecksum:
  411. tcp.Checksum = binary.BigEndian.Uint16(value[:])
  412. case tcpFieldUrgent:
  413. tcp.Urgent = binary.BigEndian.Uint16(value[:])
  414. }
  415. }
  416. func (t *transformationTCPField) setsCalculatedField() bool {
  417. return t.fieldName == tcpFieldDataOffset || t.fieldName == tcpFieldChecksum
  418. }
  419. type transformationTCPOption struct {
  420. optionName string
  421. transformationType int
  422. value []byte
  423. }
  424. const (
  425. tcpOptionEOL = "eol"
  426. tcpOptionNOP = "nop"
  427. tcpOptionMSS = "mss"
  428. tcpOptionWindowScale = "windowscale"
  429. tcpOptionSACKPermitted = "sackpermitted"
  430. tcpOptionSACK = "sack"
  431. tcpOptionTimestamps = "timestamps"
  432. tcpOptionAltChecksum = "altchecksum"
  433. tcpOptionAltChecksumData = "altchecksumdata"
  434. tcpOptionMD5Header = "md5header"
  435. tcpOptionUserTimeout = "usertimeout"
  436. )
  437. func tcpOptionInfo(optionName string) (layers.TCPOptionKind, []int, bool) {
  438. var kind layers.TCPOptionKind
  439. var validLengths []int
  440. switch optionName {
  441. case tcpOptionEOL:
  442. kind = layers.TCPOptionKindEndList
  443. validLengths = nil // no option length field
  444. case tcpOptionNOP:
  445. kind = layers.TCPOptionKindNop
  446. validLengths = nil
  447. case tcpOptionMSS:
  448. kind = layers.TCPOptionKindMSS
  449. validLengths = []int{2}
  450. case tcpOptionWindowScale:
  451. kind = layers.TCPOptionKindWindowScale
  452. validLengths = []int{1}
  453. case tcpOptionSACKPermitted:
  454. kind = layers.TCPOptionKindSACKPermitted
  455. validLengths = []int{0}
  456. case tcpOptionSACK:
  457. // https://tools.ietf.org/html/rfc2018
  458. kind = layers.TCPOptionKindSACK
  459. validLengths = []int{8, 16, 24, 32}
  460. case tcpOptionTimestamps:
  461. kind = layers.TCPOptionKindTimestamps
  462. validLengths = []int{8}
  463. case tcpOptionAltChecksum:
  464. kind = layers.TCPOptionKindAltChecksum
  465. validLengths = []int{1}
  466. case tcpOptionAltChecksumData:
  467. // https://tools.ietf.org/html/rfc1145:
  468. // "this field is used only when the alternate checksum that is negotiated is longer than 16 bits"
  469. //
  470. // Geneva allows setting length 0.
  471. kind = layers.TCPOptionKindAltChecksumData
  472. validLengths = []int{0, 4}
  473. case tcpOptionMD5Header:
  474. // https://tools.ietf.org/html/rfc2385
  475. kind = layers.TCPOptionKind(19)
  476. validLengths = []int{16}
  477. case tcpOptionUserTimeout:
  478. // https://tools.ietf.org/html/rfc5482
  479. kind = layers.TCPOptionKind(28)
  480. validLengths = []int{2}
  481. default:
  482. return kind, nil, false
  483. }
  484. return kind, validLengths, true
  485. }
  486. func newTransformationTCPOption(
  487. optionName string, transformationType int, valueSpec string) (*transformationTCPOption, error) {
  488. _, validLengths, ok := tcpOptionInfo(optionName)
  489. if !ok {
  490. return nil, errors.Tracef("invalid option name: %s", optionName)
  491. }
  492. var decodedValue []byte
  493. switch transformationType {
  494. case transformationTypeOmit:
  495. case transformationTypeRandom:
  496. case transformationTypeValue:
  497. var err error
  498. decodedValue, err = hex.DecodeString(valueSpec)
  499. if err == nil {
  500. if validLengths == nil {
  501. validLengths = []int{0}
  502. }
  503. if !common.ContainsInt(validLengths, len(decodedValue)) {
  504. err = fmt.Errorf("invalid value length: %d", len(decodedValue))
  505. }
  506. }
  507. if err != nil {
  508. return nil, errors.Tracef("invalid value spec: %s: %v", valueSpec, err)
  509. }
  510. default:
  511. return nil, errors.Tracef("invalid transformation type")
  512. }
  513. return &transformationTCPOption{
  514. optionName: optionName,
  515. transformationType: transformationType,
  516. value: decodedValue,
  517. }, nil
  518. }
  519. func (t *transformationTCPOption) apply(tcp *layers.TCP, _ *gopacket.Payload) {
  520. // This transformation makes a copy of all existing TCPOption structs, so
  521. // transformed option slices are not shared between multiple packets.
  522. //
  523. // All existing options are retained in the existing order. Modified options
  524. // are overwritten in place. New options are appended to the end of the
  525. // option list.
  526. //
  527. // Total option set size is not tracked or validated and the DataOffset TCP
  528. // field can overflow.
  529. //
  530. // Limitations:
  531. // - Inserting an option at a specific position is not supported.
  532. // - OptionLengths cannot be set to arbitrary values.
  533. // - Each option transformation executes a full copy of the existing option
  534. // list, which is not efficient for a long list of option transformations.
  535. kind, validLengths, _ := tcpOptionInfo(t.optionName)
  536. var options []layers.TCPOption
  537. // The for loop iterates over all existing options plus one additional
  538. // iteration, copying or modifying existing options and then appending a new
  539. // option if required. This flag ensures that we don't both modify and append
  540. // a new option.
  541. applied := false
  542. for i := 0; i <= len(tcp.Options); i++ {
  543. if i < len(tcp.Options) {
  544. option := tcp.Options[i]
  545. if option.OptionType != kind {
  546. options = append(options, layers.TCPOption{
  547. OptionType: option.OptionType,
  548. OptionLength: option.OptionLength,
  549. OptionData: append([]byte(nil), option.OptionData...),
  550. })
  551. continue
  552. }
  553. } else if applied {
  554. // Skip the append iteration if we already applied the transformation to an
  555. // existing option.
  556. continue
  557. }
  558. // TCP options with validLengths == nil have only the "kind" byte and total
  559. // length 1. Options with validLengths have the "kind" byte, the "length"
  560. // byte, and 0 or more data bytes; in this case, "length" is 2 + the length
  561. // of the data.
  562. switch t.transformationType {
  563. case transformationTypeOmit:
  564. continue
  565. case transformationTypeRandom:
  566. if validLengths == nil {
  567. options = append(options, layers.TCPOption{
  568. OptionType: kind,
  569. OptionLength: 1,
  570. })
  571. } else {
  572. length := validLengths[prng.Range(0, len(validLengths)-1)]
  573. var data []byte
  574. if length > 0 {
  575. data = prng.Bytes(length)
  576. }
  577. options = append(options, layers.TCPOption{
  578. OptionType: kind,
  579. OptionLength: 2 + uint8(length),
  580. OptionData: data,
  581. })
  582. }
  583. applied = true
  584. case transformationTypeValue:
  585. if validLengths == nil {
  586. options = append(options, layers.TCPOption{
  587. OptionType: kind,
  588. OptionLength: 1,
  589. })
  590. } else {
  591. length := len(t.value)
  592. var data []byte
  593. if length > 0 {
  594. data = append([]byte(nil), t.value...)
  595. }
  596. options = append(options, layers.TCPOption{
  597. OptionType: kind,
  598. OptionLength: 2 + uint8(length),
  599. OptionData: data,
  600. })
  601. }
  602. applied = true
  603. }
  604. }
  605. tcp.Options = options
  606. }
  607. func (t *transformationTCPOption) setsCalculatedField() bool {
  608. return false
  609. }
  610. type transformationTCPPayload struct {
  611. transformationType int
  612. value []byte
  613. }
  614. func newTransformationTCPPayload(
  615. transformationType int, valueSpec string) (*transformationTCPPayload, error) {
  616. var decodedValue []byte
  617. switch transformationType {
  618. case transformationTypeOmit:
  619. case transformationTypeRandom:
  620. case transformationTypeValue:
  621. var err error
  622. decodedValue, err = hex.DecodeString(valueSpec)
  623. if err != nil {
  624. return nil, errors.Tracef("invalid value spec: %s: %v", valueSpec, err)
  625. }
  626. default:
  627. return nil, errors.Tracef("invalid transformation type")
  628. }
  629. return &transformationTCPPayload{
  630. transformationType: transformationType,
  631. value: decodedValue,
  632. }, nil
  633. }
  634. func (t *transformationTCPPayload) apply(tcp *layers.TCP, payload *gopacket.Payload) {
  635. var value []byte
  636. switch t.transformationType {
  637. case transformationTypeOmit:
  638. case transformationTypeRandom:
  639. // Differs from Geneva: https://github.com/Kkevsterrr/geneva/blob/de6823ba7723582054d2047083262cabffa85f36/layers/layer.py#L191-L197
  640. value = prng.Bytes(prng.Range(1, 200))
  641. case transformationTypeValue:
  642. value = t.value
  643. }
  644. if value == nil {
  645. // Omit the payload.
  646. *payload = nil
  647. } else {
  648. // Change the payload.
  649. *payload = append([]byte(nil), value...)
  650. }
  651. }
  652. func (t *transformationTCPPayload) setsCalculatedField() bool {
  653. return false
  654. }
  655. func stripEOLOption(packet gopacket.Packet) {
  656. // gopacket.NewPacket appears to decode padding (0s) as an explicit EOL
  657. // option (value 0) at the end of the option list. This helper strips that
  658. // option, allowing append-option transformations to work as expected.
  659. // gopacket TCP serialization will re-add padding as required.
  660. tcpLayer := packet.Layer(layers.LayerTypeTCP).(*layers.TCP)
  661. if len(tcpLayer.Options) > 0 &&
  662. tcpLayer.Options[len(tcpLayer.Options)-1].OptionType == layers.TCPOptionKindEndList {
  663. tcpLayer.Options = tcpLayer.Options[:len(tcpLayer.Options)-1]
  664. }
  665. }