packetman_linux.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  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. "context"
  22. "encoding/binary"
  23. "log"
  24. "net"
  25. "strconv"
  26. "strings"
  27. "sync"
  28. "syscall"
  29. "time"
  30. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  32. "github.com/florianl/go-nfqueue"
  33. "github.com/google/gopacket"
  34. "github.com/google/gopacket/layers"
  35. cache "github.com/patrickmn/go-cache"
  36. )
  37. func IsSupported() bool {
  38. return true
  39. }
  40. const (
  41. netlinkSocketIOTimeout = 10 * time.Millisecond
  42. defaultSocketMark = 0x70736970 // "PSIP"
  43. appliedSpecCacheTTL = 1 * time.Minute
  44. )
  45. // Manipulator is a SYN-ACK packet manipulator.
  46. //
  47. // NFQUEUE/Netlink is used to intercept SYN-ACK packets, on all local
  48. // interfaces, with source port equal to one of the ProtocolPorts specified in
  49. // Config. For each intercepted SYN-ACK packet, the SelectSpecName callback in
  50. // Config is invoked; the callback determines which packet transformation spec
  51. // to apply, based on, for example, client GeoIP, protocol, or other
  52. // considerations.
  53. //
  54. // Protocol network listeners use GetAppliedSpecName to determine which
  55. // transformation spec was applied to a given accepted connection.
  56. //
  57. // When a manipulations are to be applied to a SYN-ACK packet, NFQUEUE is
  58. // instructed to drop the packet and one or more new packets, created by
  59. // applying transformations to the original SYN-ACK packet, are injected via
  60. // raw sockets. Raw sockets are used as NFQUEUE supports only replacing the
  61. // original packet with one alternative packet.
  62. //
  63. // To avoid an intercept loop, injected packets are marked (SO_MARK) and the
  64. // filter for NFQUEUE excludes packets with this mark.
  65. //
  66. // To avoid breaking TCP in unexpected cases, Manipulator fails open --
  67. // allowing the original packet to proceed -- when packet parsing fails. For
  68. // the same reason, the queue-bypass NFQUEUE option is set.
  69. //
  70. // As an iptables filter ensures only SYN-ACK packets are sent to the
  71. // NFQUEUEs, the overhead of packet interception, parsing, and injection is
  72. // incurred no more than once per TCP connection.
  73. //
  74. // NFQUEUE with queue-bypass requires Linux kernel 2.6.39; 3.16 or later is
  75. // validated and recommended.
  76. type Manipulator struct {
  77. config *Config
  78. mutex sync.Mutex
  79. runContext context.Context
  80. stopRunning context.CancelFunc
  81. waitGroup *sync.WaitGroup
  82. injectIPv4FD int
  83. injectIPv6FD int
  84. nfqueue *nfqueue.Nfqueue
  85. compiledSpecsMutex sync.Mutex
  86. compiledSpecs map[string]*compiledSpec
  87. appliedSpecCache *cache.Cache
  88. }
  89. // NewManipulator creates a new Manipulator.
  90. func NewManipulator(config *Config) (*Manipulator, error) {
  91. m := &Manipulator{
  92. config: config,
  93. }
  94. err := m.SetSpecs(config.Specs)
  95. if err != nil {
  96. return nil, errors.Trace(err)
  97. }
  98. // To avoid memory exhaustion, do not retain unconsumed appliedSpecCache
  99. // entries for a longer time than it may reasonably take to complete the TCP
  100. // handshake.
  101. m.appliedSpecCache = cache.New(appliedSpecCacheTTL, appliedSpecCacheTTL/2)
  102. return m, nil
  103. }
  104. // Start initializes NFQUEUEs and raw sockets for packet manipulation. Start
  105. // returns when initialization is complete; once it returns, the caller may
  106. // assume that any SYN-ACK packets on configured ports will be intercepted. In
  107. // the case of initialization failure, Start will undo any partial
  108. // initialization. When Start succeeds, the caller must call Stop to free
  109. // resources and restore networking state.
  110. func (m *Manipulator) Start() (retErr error) {
  111. m.mutex.Lock()
  112. defer m.mutex.Unlock()
  113. if m.runContext != nil {
  114. return errors.TraceNew("already running")
  115. }
  116. if len(m.config.ProtocolPorts) == 0 {
  117. // There are no ports to intercept, so there is nothing to run. Skip
  118. // subsequent operations which assume at least one intercept port is
  119. // configured. This is a success case, and a subseqent call to Stop is a
  120. // no-op.
  121. return nil
  122. }
  123. err := m.configureIPTables(true)
  124. if err != nil {
  125. return errors.Trace(err)
  126. }
  127. defer func() {
  128. if retErr != nil {
  129. m.configureIPTables(false)
  130. }
  131. }()
  132. m.injectIPv4FD, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
  133. if err != nil {
  134. return errors.Trace(err)
  135. }
  136. defer func() {
  137. if retErr != nil {
  138. syscall.Close(m.injectIPv4FD)
  139. }
  140. }()
  141. err = syscall.SetsockoptInt(m.injectIPv4FD, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
  142. if err != nil {
  143. return errors.Trace(err)
  144. }
  145. err = syscall.SetsockoptInt(m.injectIPv4FD, syscall.SOL_SOCKET, syscall.SO_MARK, m.getSocketMark())
  146. if err != nil {
  147. return errors.Trace(err)
  148. }
  149. m.injectIPv6FD, err = syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
  150. if err != nil && !m.config.AllowNoIPv6NetworkConfiguration {
  151. return errors.Trace(err)
  152. }
  153. defer func() {
  154. if retErr != nil {
  155. syscall.Close(m.injectIPv6FD)
  156. }
  157. }()
  158. if m.injectIPv6FD != 0 {
  159. err = syscall.SetsockoptInt(m.injectIPv6FD, syscall.IPPROTO_IPV6, syscall.IP_HDRINCL, 1)
  160. if err != nil {
  161. // There's no AllowNoIPv6NetworkConfiguration in this case: if we can
  162. // create an IPv6 socket, we must be able to set its options.
  163. return errors.Trace(err)
  164. }
  165. err = syscall.SetsockoptInt(m.injectIPv6FD, syscall.SOL_SOCKET, syscall.SO_MARK, m.getSocketMark())
  166. if err != nil {
  167. return errors.Trace(err)
  168. }
  169. }
  170. // Use a reasonable buffer size to avoid excess allocation. As we're
  171. // intercepting only locally generated SYN-ACK packets, which should have no
  172. // payload, this size should be more than sufficient.
  173. maxPacketLen := uint32(1500)
  174. // Use the kernel default of 1024:
  175. // https://github.com/torvalds/linux/blob/cd8dead0c39457e58ec1d36db93aedca811d48f1/net/netfilter/nfnetlink_queue.c#L51,
  176. // via https://github.com/florianl/go-nfqueue/issues/3.
  177. maxQueueLen := uint32(1024)
  178. // Note: runContext alone is not sufficient to interrupt the
  179. // nfqueue.socketCallback goroutine spawned by nfqueue.Register; timeouts
  180. // must be set. See comment in Manipulator.Stop.
  181. m.nfqueue, err = nfqueue.Open(
  182. &nfqueue.Config{
  183. NfQueue: uint16(m.config.QueueNumber),
  184. MaxPacketLen: maxPacketLen,
  185. MaxQueueLen: maxQueueLen,
  186. Copymode: nfqueue.NfQnlCopyPacket,
  187. Logger: newNfqueueLogger(m.config.Logger),
  188. ReadTimeout: netlinkSocketIOTimeout,
  189. WriteTimeout: netlinkSocketIOTimeout,
  190. })
  191. if err != nil {
  192. return errors.Trace(err)
  193. }
  194. defer func() {
  195. if retErr != nil {
  196. m.nfqueue.Close()
  197. }
  198. }()
  199. runContext, stopRunning := context.WithCancel(context.Background())
  200. defer func() {
  201. if retErr != nil {
  202. stopRunning()
  203. }
  204. }()
  205. err = m.nfqueue.Register(runContext, m.handleInterceptedPacket)
  206. if err != nil {
  207. return errors.Trace(err)
  208. }
  209. m.runContext = runContext
  210. m.stopRunning = stopRunning
  211. return nil
  212. }
  213. // Stop halts packet manipulation, frees resources, and restores networking
  214. // state.
  215. func (m *Manipulator) Stop() {
  216. m.mutex.Lock()
  217. defer m.mutex.Unlock()
  218. if m.runContext == nil {
  219. return
  220. }
  221. m.stopRunning()
  222. // stopRunning will cancel the context passed into nfqueue.Register. The
  223. // goroutine spawned by Register, nfqueue.socketCallback, polls the context
  224. // after a read timeout:
  225. // https://github.com/florianl/go-nfqueue/blob/1e38df738c06deffbac08da8fec4b7c28a69b918/nfqueue_gteq_1.12.go#L138-L146
  226. //
  227. // There's no stop synchronization exposed by nfqueue. Calling nfqueue.Close
  228. // while socketCallback is still running can result in errors such as
  229. // "nfqueuenfqueue_gteq_1.12.go:134: Could not unbind from queue: netlink
  230. // send: sendmsg: bad file descriptor".
  231. //
  232. // To avoid invalid file descriptor operations and spurious error messages,
  233. // sleep for two polling periods, which should be sufficient, in most cases,
  234. // for socketCallback to poll the context and exit.
  235. time.Sleep(2 * netlinkSocketIOTimeout)
  236. m.nfqueue.Close()
  237. syscall.Close(m.injectIPv4FD)
  238. if m.injectIPv6FD != 0 {
  239. syscall.Close(m.injectIPv6FD)
  240. }
  241. m.configureIPTables(false)
  242. }
  243. // SetSpecs installs a new set of packet transformation Spec values, replacing
  244. // the initial specs from Config.Specs, or any previous SetSpecs call. When
  245. // SetSpecs returns an error, the previous set of specs is retained.
  246. func (m *Manipulator) SetSpecs(specs []*Spec) error {
  247. compiledSpecs := make(map[string]*compiledSpec)
  248. for _, spec := range specs {
  249. if spec.Name == "" {
  250. return errors.TraceNew("invalid spec name")
  251. }
  252. if _, ok := compiledSpecs[spec.Name]; ok {
  253. return errors.TraceNew("duplicate spec name")
  254. }
  255. compiledSpec, err := compileSpec(spec)
  256. if err != nil {
  257. return errors.Trace(err)
  258. }
  259. compiledSpecs[spec.Name] = compiledSpec
  260. }
  261. m.compiledSpecsMutex.Lock()
  262. m.compiledSpecs = compiledSpecs
  263. m.compiledSpecsMutex.Unlock()
  264. return nil
  265. }
  266. func makeConnectionID(
  267. srcIP net.IP, srcPort uint16, dstIP net.IP, dstPort uint16) string {
  268. // Create a unique connection ID, for appliedSpecCache, from the 4-tuple
  269. // srcIP, dstIP, srcPort, dstPort. In the SYN/ACK context, src is the server
  270. // and dst is the client.
  271. //
  272. // Limitation: there may be many repeat connections from one dstIP,
  273. // especially if many clients are behind the same NAT. Each TCP connection
  274. // will have a distinct dstPort. In principle, there remains a race between
  275. // populating appliedSpecCache, the TCP connection terminating on the
  276. // client-side and the NAT reusing the dstPort, and consuming
  277. // appliedSpecCache.
  278. // From: https://github.com/golang/go/blob/b88efc7e7ac15f9e0b5d8d9c82f870294f6a3839/src/net/ip.go#L55
  279. var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
  280. const uint16Len = 2
  281. var connID [net.IPv6len + uint16Len + net.IPv6len + uint16Len]byte
  282. offset := 0
  283. if len(srcIP) == net.IPv4len {
  284. copy(connID[offset:], v4InV6Prefix)
  285. offset += len(v4InV6Prefix)
  286. copy(connID[offset:], srcIP)
  287. offset += len(srcIP)
  288. } else { // net.IPv6len
  289. copy(connID[offset:], srcIP)
  290. offset += len(srcIP)
  291. }
  292. binary.BigEndian.PutUint16(connID[offset:], srcPort)
  293. offset += uint16Len
  294. if len(dstIP) == net.IPv4len {
  295. copy(connID[offset:], v4InV6Prefix)
  296. offset += len(v4InV6Prefix)
  297. copy(connID[offset:], dstIP)
  298. offset += len(dstIP)
  299. } else { // net.IPv6len
  300. copy(connID[offset:], dstIP)
  301. offset += len(dstIP)
  302. }
  303. binary.BigEndian.PutUint16(connID[offset:], dstPort)
  304. offset += uint16Len
  305. return string(connID[:])
  306. }
  307. // GetAppliedSpecName returns the packet manipulation spec name applied to the
  308. // TCP connection, represented by its local and remote address components,
  309. // that was ultimately accepted by a network listener.
  310. //
  311. // This allows SelectSpecName, the spec selector, to be non-deterministic
  312. // while also allowing for accurate packet manipulation metrics to be
  313. // associated with each TCP connection.
  314. //
  315. // For a given connection, GetAppliedSpecName must be called before a TTL
  316. // clears the stored value. Calling GetAppliedSpecName immediately clears the
  317. // stored value for the given connection.
  318. //
  319. // To obtain the correct result GetAppliedSpecName must be called with a
  320. // RemoteAddr which reflects the true immediate network peer address. In
  321. // particular, for proxied net.Conns which present a synthetic RemoteAddr with
  322. // the original address of a proxied client (e.g., armon/go-proxyproto, or
  323. // psiphon/server.meekConn) the true peer RemoteAddr must instead be
  324. // provided.
  325. func (m *Manipulator) GetAppliedSpecName(
  326. localAddr, remoteAddr *net.TCPAddr) (string, error) {
  327. connID := makeConnectionID(
  328. localAddr.IP,
  329. uint16(localAddr.Port),
  330. remoteAddr.IP,
  331. uint16(remoteAddr.Port))
  332. specName, found := m.appliedSpecCache.Get(connID)
  333. if !found {
  334. return "", errors.TraceNew("connection not found")
  335. }
  336. m.appliedSpecCache.Delete(connID)
  337. return specName.(string), nil
  338. }
  339. func (m *Manipulator) setAppliedSpecName(
  340. interceptedPacket gopacket.Packet, specName string) {
  341. srcIP, dstIP, _, _ := m.getPacketAddressInfo(interceptedPacket)
  342. interceptedTCP := interceptedPacket.Layer(layers.LayerTypeTCP).(*layers.TCP)
  343. connID := makeConnectionID(
  344. srcIP,
  345. uint16(interceptedTCP.SrcPort),
  346. dstIP,
  347. uint16(interceptedTCP.DstPort))
  348. m.appliedSpecCache.Set(connID, specName, cache.DefaultExpiration)
  349. }
  350. func (m *Manipulator) getSocketMark() int {
  351. if m.config.SocketMark == 0 {
  352. return defaultSocketMark
  353. }
  354. return m.config.SocketMark
  355. }
  356. func (m *Manipulator) handleInterceptedPacket(attr nfqueue.Attribute) int {
  357. if attr.PacketID == nil || attr.Payload == nil {
  358. m.config.Logger.WithTrace().Warning("missing nfqueue data")
  359. return 0
  360. }
  361. // Trigger packet manipulation only if the packet is a SYN-ACK and has no
  362. // payload (which a transformation _may_ discard). The iptables filter for
  363. // NFQUEUE should already ensure that only SYN-ACK packets are sent through
  364. // the queue. To avoid breaking all TCP connections in an unanticipated case,
  365. // fail open -- allow the packet -- if these conditions are not met or if
  366. // parsing the packet fails.
  367. packet, err := m.parseInterceptedPacket(*attr.Payload)
  368. if err != nil {
  369. // Fail open in this case.
  370. m.nfqueue.SetVerdict(*attr.PacketID, nfqueue.NfAccept)
  371. m.config.Logger.WithTraceFields(
  372. common.LogFields{"error": err}).Warning("unexpected packet")
  373. return 0
  374. }
  375. spec, err := m.getCompiledSpec(packet)
  376. if err != nil {
  377. // Fail open in this case.
  378. m.nfqueue.SetVerdict(*attr.PacketID, nfqueue.NfAccept)
  379. m.config.Logger.WithTraceFields(
  380. common.LogFields{"error": err}).Warning("get strategy failed")
  381. return 0
  382. }
  383. // Call setAppliedSpecName cache _before_ accepting the packet or injecting
  384. // manipulated packets to avoid a potential race in which the TCP handshake
  385. // completes and GetAppliedSpecName is called before the cache is populated.
  386. if spec == nil {
  387. // No packet manipulation in this case.
  388. m.setAppliedSpecName(packet, "")
  389. m.nfqueue.SetVerdict(*attr.PacketID, nfqueue.NfAccept)
  390. return 0
  391. }
  392. m.setAppliedSpecName(packet, spec.name)
  393. m.nfqueue.SetVerdict(*attr.PacketID, nfqueue.NfDrop)
  394. err = m.injectPackets(packet, spec)
  395. if err != nil {
  396. m.config.Logger.WithTraceFields(
  397. common.LogFields{"error": err}).Warning("inject packets failed")
  398. return 0
  399. }
  400. return 0
  401. }
  402. func (m *Manipulator) parseInterceptedPacket(packetData []byte) (gopacket.Packet, error) {
  403. // Note that NFQUEUE doesn't send an Ethernet layer. This first layer is
  404. // either IPv4 or IPv6.
  405. //
  406. // As we parse only one packet per TCP connection, we are not using the
  407. // faster DecodingLayerParser API,
  408. // https://godoc.org/github.com/google/gopacket#hdr-Fast_Decoding_With_DecodingLayerParser,
  409. // or zero-copy approaches.
  410. //
  411. // TODO: use a stub gopacket.Decoder as the first layer to avoid the extra
  412. // NewPacket call? Use distinct NFQUEUE queue numbers and nfqueue instances
  413. // for IPv4 and IPv6?
  414. packet := gopacket.NewPacket(packetData, layers.LayerTypeIPv4, gopacket.Default)
  415. if packet.ErrorLayer() != nil {
  416. packet = gopacket.NewPacket(packetData, layers.LayerTypeIPv6, gopacket.Default)
  417. }
  418. errLayer := packet.ErrorLayer()
  419. if errLayer != nil {
  420. return nil, errors.Trace(errLayer.Error())
  421. }
  422. // After this check, Layer([IPv4,IPv6]/TCP) return values are assumed to be
  423. // non-nil and unchecked layer type assertions are assumed safe.
  424. tcpLayer := packet.Layer(layers.LayerTypeTCP)
  425. if tcpLayer == nil {
  426. return nil, errors.TraceNew("missing TCP layer")
  427. }
  428. if packet.Layer(gopacket.LayerTypePayload) != nil {
  429. return nil, errors.TraceNew("unexpected payload layer")
  430. }
  431. tcp := tcpLayer.(*layers.TCP)
  432. // Any of the ECN TCP flags (https://tools.ietf.org/html/rfc3168 and
  433. // rfc3540), ECE/CWR/NS, may be set in a SYN-ACK, and are retained.
  434. //
  435. // Limitation: these additional flags are retained as-is on injected packets
  436. // only when no TCP flag transformation is applied.
  437. if !tcp.SYN || !tcp.ACK ||
  438. tcp.FIN || tcp.RST || tcp.PSH || tcp.URG {
  439. return nil, errors.TraceNew("unexpected TCP flags")
  440. }
  441. stripEOLOption(packet)
  442. return packet, nil
  443. }
  444. func (m *Manipulator) getCompiledSpec(interceptedPacket gopacket.Packet) (*compiledSpec, error) {
  445. _, dstIP, _, _ := m.getPacketAddressInfo(interceptedPacket)
  446. interceptedTCP := interceptedPacket.Layer(layers.LayerTypeTCP).(*layers.TCP)
  447. protocolPort := interceptedTCP.SrcPort
  448. clientIP := dstIP
  449. specName := m.config.SelectSpecName(int(protocolPort), clientIP)
  450. if specName == "" {
  451. return nil, nil
  452. }
  453. // Concurrency note: m.compiledSpecs may be replaced by SetSpecs, but any
  454. // reference to an individual compiledSpec remains valid; each compiledSpec
  455. // is read-only.
  456. m.compiledSpecsMutex.Lock()
  457. spec, ok := m.compiledSpecs[specName]
  458. m.compiledSpecsMutex.Unlock()
  459. if !ok {
  460. return nil, errors.Tracef("invalid spec name: %s", specName)
  461. }
  462. return spec, nil
  463. }
  464. func (m *Manipulator) injectPackets(interceptedPacket gopacket.Packet, spec *compiledSpec) error {
  465. // A sockAddr parameter with dstIP (but not port) set appears to be required
  466. // even with the IP_HDRINCL socket option.
  467. _, _, injectFD, sockAddr := m.getPacketAddressInfo(interceptedPacket)
  468. injectPackets, err := spec.apply(interceptedPacket)
  469. if err != nil {
  470. return errors.Trace(err)
  471. }
  472. for _, injectPacket := range injectPackets {
  473. err = syscall.Sendto(injectFD, injectPacket, 0, sockAddr)
  474. if err != nil {
  475. return errors.Trace(err)
  476. }
  477. }
  478. return nil
  479. }
  480. func (m *Manipulator) getPacketAddressInfo(interceptedPacket gopacket.Packet) (net.IP, net.IP, int, syscall.Sockaddr) {
  481. var srcIP, dstIP net.IP
  482. var injectFD int
  483. var sockAddr syscall.Sockaddr
  484. ipv4Layer := interceptedPacket.Layer(layers.LayerTypeIPv4)
  485. if ipv4Layer != nil {
  486. interceptedIPv4 := ipv4Layer.(*layers.IPv4)
  487. srcIP = interceptedIPv4.SrcIP
  488. dstIP = interceptedIPv4.DstIP
  489. injectFD = m.injectIPv4FD
  490. var ipv4 [4]byte
  491. copy(ipv4[:], interceptedIPv4.DstIP.To4())
  492. sockAddr = &syscall.SockaddrInet4{Addr: ipv4, Port: 0}
  493. } else {
  494. interceptedIPv6 := interceptedPacket.Layer(layers.LayerTypeIPv6).(*layers.IPv6)
  495. srcIP = interceptedIPv6.SrcIP
  496. dstIP = interceptedIPv6.DstIP
  497. injectFD = m.injectIPv6FD
  498. var ipv6 [16]byte
  499. copy(ipv6[:], interceptedIPv6.DstIP.To16())
  500. sockAddr = &syscall.SockaddrInet6{Addr: ipv6, Port: 0}
  501. }
  502. return srcIP, dstIP, injectFD, sockAddr
  503. }
  504. func (m *Manipulator) configureIPTables(addRules bool) error {
  505. execCommands := func(mode string) error {
  506. ports := make([]string, len(m.config.ProtocolPorts))
  507. for i, port := range m.config.ProtocolPorts {
  508. ports[i] = strconv.Itoa(port)
  509. }
  510. socketMark := strconv.Itoa(m.getSocketMark())
  511. args := []string{
  512. mode, "OUTPUT",
  513. "--protocol", "tcp",
  514. "--match", "multiport",
  515. "--source-ports", strings.Join(ports, ","),
  516. "--match", "mark",
  517. "!", "--mark", socketMark,
  518. "--tcp-flags", "ALL", "SYN,ACK",
  519. "-j", "NFQUEUE",
  520. "--queue-bypass",
  521. "--queue-num", strconv.Itoa(m.config.QueueNumber),
  522. }
  523. err := common.RunNetworkConfigCommand(
  524. m.config.Logger,
  525. m.config.SudoNetworkConfigCommands,
  526. "iptables",
  527. args...)
  528. if mode != "-D" && err != nil {
  529. return errors.Trace(err)
  530. }
  531. err = common.RunNetworkConfigCommand(
  532. m.config.Logger,
  533. m.config.SudoNetworkConfigCommands,
  534. "ip6tables",
  535. args...)
  536. if mode != "-D" && err != nil {
  537. if m.config.AllowNoIPv6NetworkConfiguration {
  538. m.config.Logger.WithTraceFields(
  539. common.LogFields{
  540. "error": err}).Warning(
  541. "configure IPv6 NFQUEUE failed")
  542. } else {
  543. return errors.Trace(err)
  544. }
  545. }
  546. return nil
  547. }
  548. // To avoid duplicates, first try to drop existing rules, then add. Also try
  549. // to revert any partial configuration in the case of an error.
  550. _ = execCommands("-D")
  551. if addRules {
  552. err := execCommands("-I")
  553. if err != nil {
  554. _ = execCommands("-D")
  555. }
  556. return errors.Trace(err)
  557. }
  558. return nil
  559. }
  560. func newNfqueueLogger(logger common.Logger) *log.Logger {
  561. return log.New(
  562. &nfqueueLoggerWriter{logger: logger},
  563. "nfqueue",
  564. log.Lshortfile)
  565. }
  566. type nfqueueLoggerWriter struct {
  567. logger common.Logger
  568. }
  569. func (n *nfqueueLoggerWriter) Write(p []byte) (int, error) {
  570. n.logger.WithTraceFields(
  571. common.LogFields{"log": string(p)}).Warning("nfqueue log")
  572. return len(p), nil
  573. }