packetman.go 23 KB

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