iptables.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build linux && !(386 || loong64 || arm || armbe)
  4. package linuxfw
  5. import (
  6. "encoding/hex"
  7. "errors"
  8. "fmt"
  9. "net"
  10. "net/netip"
  11. "strings"
  12. "unsafe"
  13. "github.com/josharian/native"
  14. "golang.org/x/sys/unix"
  15. linuxabi "gvisor.dev/gvisor/pkg/abi/linux"
  16. "tailscale.com/net/netaddr"
  17. "tailscale.com/types/logger"
  18. )
  19. type sockLen uint32
  20. var (
  21. iptablesChainNames = map[int]string{
  22. linuxabi.NF_INET_PRE_ROUTING: "PREROUTING",
  23. linuxabi.NF_INET_LOCAL_IN: "INPUT",
  24. linuxabi.NF_INET_FORWARD: "FORWARD",
  25. linuxabi.NF_INET_LOCAL_OUT: "OUTPUT",
  26. linuxabi.NF_INET_POST_ROUTING: "POSTROUTING",
  27. }
  28. iptablesStandardChains = (func() map[string]bool {
  29. ret := make(map[string]bool)
  30. for _, v := range iptablesChainNames {
  31. ret[v] = true
  32. }
  33. return ret
  34. })()
  35. )
  36. // DebugNetfilter prints debug information about iptables rules to the
  37. // provided log function.
  38. func DebugIptables(logf logger.Logf) error {
  39. for _, table := range []string{"filter", "nat", "raw"} {
  40. type chainAndEntry struct {
  41. chain string
  42. entry *entry
  43. }
  44. // Collect all entries first so we can resolve jumps
  45. var (
  46. lastChain string
  47. ces []chainAndEntry
  48. chainOffsets = make(map[int]string)
  49. )
  50. err := enumerateIptablesTable(logf, table, func(chain string, entry *entry) error {
  51. if chain != lastChain {
  52. chainOffsets[entry.Offset] = chain
  53. lastChain = chain
  54. }
  55. ces = append(ces, chainAndEntry{
  56. chain: lastChain,
  57. entry: entry,
  58. })
  59. return nil
  60. })
  61. if err != nil {
  62. return err
  63. }
  64. lastChain = ""
  65. for _, ce := range ces {
  66. if ce.chain != lastChain {
  67. logf("iptables: table=%s chain=%s", table, ce.chain)
  68. lastChain = ce.chain
  69. }
  70. // Fixup jump
  71. if std, ok := ce.entry.Target.Data.(standardTarget); ok {
  72. if strings.HasPrefix(std.Verdict, "JUMP(") {
  73. var off int
  74. if _, err := fmt.Sscanf(std.Verdict, "JUMP(%d)", &off); err == nil {
  75. if jt, ok := chainOffsets[off]; ok {
  76. std.Verdict = "JUMP(" + jt + ")"
  77. ce.entry.Target.Data = std
  78. }
  79. }
  80. }
  81. }
  82. logf("iptables: entry=%+v", ce.entry)
  83. }
  84. }
  85. return nil
  86. }
  87. // DetectIptables returns the number of iptables rules that are present in the
  88. // system, ignoring the default "ACCEPT" rule present in the standard iptables
  89. // chains.
  90. //
  91. // It only returns an error when the kernel returns an error (i.e. when a
  92. // syscall fails); when there are no iptables rules, it is valid for this
  93. // function to return 0, nil.
  94. func DetectIptables() (int, error) {
  95. dummyLog := func(string, ...any) {}
  96. var (
  97. validRules int
  98. firstErr error
  99. )
  100. for _, table := range []string{"filter", "nat", "raw"} {
  101. err := enumerateIptablesTable(dummyLog, table, func(chain string, entry *entry) error {
  102. // If we have any rules other than basic 'ACCEPT' entries in a
  103. // standard chain, then we consider this a valid rule.
  104. switch {
  105. case !iptablesStandardChains[chain]:
  106. validRules++
  107. case entry.Target.Name != "standard":
  108. validRules++
  109. case entry.Target.Name == "standard" && entry.Target.Data.(standardTarget).Verdict != "ACCEPT":
  110. validRules++
  111. }
  112. return nil
  113. })
  114. if err != nil && firstErr == nil {
  115. firstErr = err
  116. }
  117. }
  118. return validRules, firstErr
  119. }
  120. func enumerateIptablesTable(logf logger.Logf, table string, cb func(string, *entry) error) error {
  121. ln, err := net.Listen("tcp4", ":0")
  122. if err != nil {
  123. return err
  124. }
  125. defer ln.Close()
  126. tcpLn := ln.(*net.TCPListener)
  127. conn, err := tcpLn.SyscallConn()
  128. if err != nil {
  129. return err
  130. }
  131. var tableName linuxabi.TableName
  132. copy(tableName[:], []byte(table))
  133. tbl := linuxabi.IPTGetinfo{
  134. Name: tableName,
  135. }
  136. slt := sockLen(linuxabi.SizeOfIPTGetinfo)
  137. var ctrlErr error
  138. err = conn.Control(func(fd uintptr) {
  139. _, _, errno := unix.Syscall6(
  140. unix.SYS_GETSOCKOPT,
  141. fd,
  142. uintptr(unix.SOL_IP),
  143. linuxabi.IPT_SO_GET_INFO,
  144. uintptr(unsafe.Pointer(&tbl)),
  145. uintptr(unsafe.Pointer(&slt)),
  146. 0,
  147. )
  148. if errno != 0 {
  149. ctrlErr = errno
  150. return
  151. }
  152. })
  153. if err != nil {
  154. return err
  155. }
  156. if ctrlErr != nil {
  157. return ctrlErr
  158. }
  159. if tbl.Size < 1 {
  160. return nil
  161. }
  162. // Allocate enough space to be able to get all iptables information.
  163. entsBuf := make([]byte, linuxabi.SizeOfIPTGetEntries+tbl.Size)
  164. entsHdr := (*linuxabi.IPTGetEntries)(unsafe.Pointer(&entsBuf[0]))
  165. entsHdr.Name = tableName
  166. entsHdr.Size = tbl.Size
  167. slt = sockLen(len(entsBuf))
  168. err = conn.Control(func(fd uintptr) {
  169. _, _, errno := unix.Syscall6(
  170. unix.SYS_GETSOCKOPT,
  171. fd,
  172. uintptr(unix.SOL_IP),
  173. linuxabi.IPT_SO_GET_ENTRIES,
  174. uintptr(unsafe.Pointer(&entsBuf[0])),
  175. uintptr(unsafe.Pointer(&slt)),
  176. 0,
  177. )
  178. if errno != 0 {
  179. ctrlErr = errno
  180. return
  181. }
  182. })
  183. if err != nil {
  184. return err
  185. }
  186. if ctrlErr != nil {
  187. return ctrlErr
  188. }
  189. // Skip header
  190. entsBuf = entsBuf[linuxabi.SizeOfIPTGetEntries:]
  191. var (
  192. totalOffset int
  193. currentChain string
  194. )
  195. for len(entsBuf) > 0 {
  196. parser := entryParser{
  197. buf: entsBuf,
  198. logf: logf,
  199. checkExtraBytes: true,
  200. }
  201. entry, err := parser.parseEntry(entsBuf)
  202. if err != nil {
  203. logf("iptables: err=%v", err)
  204. break
  205. }
  206. entry.Offset += totalOffset
  207. // Don't pass 'ERROR' nodes to our caller
  208. if entry.Target.Name == "ERROR" {
  209. if parser.offset == len(entsBuf) {
  210. // all done
  211. break
  212. }
  213. // New user-defined chain
  214. currentChain = entry.Target.Data.(errorTarget).ErrorName
  215. } else {
  216. // Detect if we're at a new chain based on the hook
  217. // offsets we fetched earlier.
  218. for i, he := range tbl.HookEntry {
  219. if int(he) == totalOffset {
  220. currentChain = iptablesChainNames[i]
  221. }
  222. }
  223. // Now that we have everything, call our callback.
  224. if err := cb(currentChain, &entry); err != nil {
  225. return err
  226. }
  227. }
  228. entsBuf = entsBuf[parser.offset:]
  229. totalOffset += parser.offset
  230. }
  231. return nil
  232. }
  233. // TODO(andrew): convert to use cstruct
  234. type entryParser struct {
  235. buf []byte
  236. offset int
  237. logf logger.Logf
  238. // Set to 'true' to print debug messages about unused bytes returned
  239. // from the kernel
  240. checkExtraBytes bool
  241. }
  242. func (p *entryParser) haveLen(ln int) bool {
  243. if len(p.buf)-p.offset < ln {
  244. return false
  245. }
  246. return true
  247. }
  248. func (p *entryParser) assertLen(ln int) error {
  249. if !p.haveLen(ln) {
  250. return fmt.Errorf("need %d bytes: %w", ln, errBufferTooSmall)
  251. }
  252. return nil
  253. }
  254. func (p *entryParser) getBytes(amt int) []byte {
  255. ret := p.buf[p.offset : p.offset+amt]
  256. p.offset += amt
  257. return ret
  258. }
  259. func (p *entryParser) getByte() byte {
  260. ret := p.buf[p.offset]
  261. p.offset += 1
  262. return ret
  263. }
  264. func (p *entryParser) get4() (ret [4]byte) {
  265. ret[0] = p.buf[p.offset+0]
  266. ret[1] = p.buf[p.offset+1]
  267. ret[2] = p.buf[p.offset+2]
  268. ret[3] = p.buf[p.offset+3]
  269. p.offset += 4
  270. return
  271. }
  272. func (p *entryParser) setOffset(off, max int) error {
  273. // We can't go back
  274. if off < p.offset {
  275. return fmt.Errorf("invalid target offset (%d < %d): %w", off, p.offset, errMalformed)
  276. }
  277. // Ensure we don't go beyond our maximum, if given
  278. if max >= 0 && off >= max {
  279. return fmt.Errorf("invalid target offset (%d >= %d): %w", off, max, errMalformed)
  280. }
  281. // If we aren't already at this offset, move forward
  282. if p.offset < off {
  283. if p.checkExtraBytes {
  284. extraData := p.buf[p.offset:off]
  285. diff := off - p.offset
  286. p.logf("%d bytes (%d, %d) are unused: %s", diff, p.offset, off, hex.EncodeToString(extraData))
  287. }
  288. p.offset = off
  289. }
  290. return nil
  291. }
  292. var (
  293. errBufferTooSmall = errors.New("buffer too small")
  294. errMalformed = errors.New("data malformed")
  295. )
  296. type entry struct {
  297. Offset int
  298. IP iptip
  299. NFCache uint32
  300. PacketCount uint64
  301. ByteCount uint64
  302. Matches []match
  303. Target target
  304. }
  305. func (e entry) String() string {
  306. var sb strings.Builder
  307. sb.WriteString("{")
  308. fmt.Fprintf(&sb, "Offset:%d IP:%v PacketCount:%d ByteCount:%d", e.Offset, e.IP, e.PacketCount, e.ByteCount)
  309. if len(e.Matches) > 0 {
  310. fmt.Fprintf(&sb, " Matches:%v", e.Matches)
  311. }
  312. fmt.Fprintf(&sb, " Target:%v", e.Target)
  313. sb.WriteString("}")
  314. return sb.String()
  315. }
  316. func (p *entryParser) parseEntry(b []byte) (entry, error) {
  317. startOff := p.offset
  318. iptip, err := p.parseIPTIP()
  319. if err != nil {
  320. return entry{}, fmt.Errorf("parsing IPTIP: %w", err)
  321. }
  322. ret := entry{
  323. Offset: startOff,
  324. IP: iptip,
  325. }
  326. // Must have space for the rest of the members
  327. if err := p.assertLen(28); err != nil {
  328. return entry{}, err
  329. }
  330. ret.NFCache = native.Endian.Uint32(p.getBytes(4))
  331. targetOffset := int(native.Endian.Uint16(p.getBytes(2)))
  332. nextOffset := int(native.Endian.Uint16(p.getBytes(2)))
  333. /* unused field: Comeback = */ p.getBytes(4)
  334. ret.PacketCount = native.Endian.Uint64(p.getBytes(8))
  335. ret.ByteCount = native.Endian.Uint64(p.getBytes(8))
  336. // Must have at least enough space in our buffer to get to the target;
  337. // doing this here means we can avoid bounds checks in parseMatches
  338. if err := p.assertLen(targetOffset - p.offset); err != nil {
  339. return entry{}, err
  340. }
  341. // Matches are stored between the end of the entry structure and the
  342. // start of the 'targets' structure.
  343. ret.Matches, err = p.parseMatches(targetOffset)
  344. if err != nil {
  345. return entry{}, err
  346. }
  347. if targetOffset > 0 {
  348. if err := p.setOffset(targetOffset, nextOffset); err != nil {
  349. return entry{}, err
  350. }
  351. ret.Target, err = p.parseTarget(nextOffset)
  352. if err != nil {
  353. return entry{}, fmt.Errorf("parsing target: %w", err)
  354. }
  355. }
  356. if err := p.setOffset(nextOffset, -1); err != nil {
  357. return entry{}, err
  358. }
  359. return ret, nil
  360. }
  361. type iptip struct {
  362. Src netip.Addr
  363. Dst netip.Addr
  364. SrcMask netip.Addr
  365. DstMask netip.Addr
  366. InputInterface string
  367. OutputInterface string
  368. InputInterfaceMask []byte
  369. OutputInterfaceMask []byte
  370. Protocol uint16
  371. Flags uint8
  372. InverseFlags uint8
  373. }
  374. var protocolNames = map[uint16]string{
  375. unix.IPPROTO_ESP: "esp",
  376. unix.IPPROTO_GRE: "gre",
  377. unix.IPPROTO_ICMP: "icmp",
  378. unix.IPPROTO_ICMPV6: "icmpv6",
  379. unix.IPPROTO_IGMP: "igmp",
  380. unix.IPPROTO_IP: "ip",
  381. unix.IPPROTO_IPIP: "ipip",
  382. unix.IPPROTO_IPV6: "ip6",
  383. unix.IPPROTO_RAW: "raw",
  384. unix.IPPROTO_TCP: "tcp",
  385. unix.IPPROTO_UDP: "udp",
  386. }
  387. func (ip iptip) String() string {
  388. var sb strings.Builder
  389. sb.WriteString("{")
  390. formatAddrMask := func(addr, mask netip.Addr) string {
  391. if pref, ok := netaddr.FromStdIPNet(&net.IPNet{
  392. IP: addr.AsSlice(),
  393. Mask: mask.AsSlice(),
  394. }); ok {
  395. return fmt.Sprint(pref)
  396. }
  397. return fmt.Sprintf("%s/%s", addr, mask)
  398. }
  399. fmt.Fprintf(&sb, "Src:%s", formatAddrMask(ip.Src, ip.SrcMask))
  400. fmt.Fprintf(&sb, ", Dst:%s", formatAddrMask(ip.Dst, ip.DstMask))
  401. translateMask := func(mask []byte) string {
  402. var ret []byte
  403. for _, b := range mask {
  404. if b != 0 {
  405. ret = append(ret, 'X')
  406. } else {
  407. ret = append(ret, '.')
  408. }
  409. }
  410. return string(ret)
  411. }
  412. if ip.InputInterface != "" {
  413. fmt.Fprintf(&sb, ", InputInterface:%s/%s", ip.InputInterface, translateMask(ip.InputInterfaceMask))
  414. }
  415. if ip.OutputInterface != "" {
  416. fmt.Fprintf(&sb, ", OutputInterface:%s/%s", ip.OutputInterface, translateMask(ip.OutputInterfaceMask))
  417. }
  418. if nm, ok := protocolNames[ip.Protocol]; ok {
  419. fmt.Fprintf(&sb, ", Protocol:%s", nm)
  420. } else {
  421. fmt.Fprintf(&sb, ", Protocol:%d", ip.Protocol)
  422. }
  423. if ip.Flags != 0 {
  424. fmt.Fprintf(&sb, ", Flags:%d", ip.Flags)
  425. }
  426. if ip.InverseFlags != 0 {
  427. fmt.Fprintf(&sb, ", InverseFlags:%d", ip.InverseFlags)
  428. }
  429. sb.WriteString("}")
  430. return sb.String()
  431. }
  432. func (p *entryParser) parseIPTIP() (iptip, error) {
  433. if err := p.assertLen(84); err != nil {
  434. return iptip{}, err
  435. }
  436. var ret iptip
  437. ret.Src = netip.AddrFrom4(p.get4())
  438. ret.Dst = netip.AddrFrom4(p.get4())
  439. ret.SrcMask = netip.AddrFrom4(p.get4())
  440. ret.DstMask = netip.AddrFrom4(p.get4())
  441. const IFNAMSIZ = 16
  442. ret.InputInterface = unix.ByteSliceToString(p.getBytes(IFNAMSIZ))
  443. ret.OutputInterface = unix.ByteSliceToString(p.getBytes(IFNAMSIZ))
  444. ret.InputInterfaceMask = p.getBytes(IFNAMSIZ)
  445. ret.OutputInterfaceMask = p.getBytes(IFNAMSIZ)
  446. ret.Protocol = native.Endian.Uint16(p.getBytes(2))
  447. ret.Flags = p.getByte()
  448. ret.InverseFlags = p.getByte()
  449. return ret, nil
  450. }
  451. type match struct {
  452. Name string
  453. Revision int
  454. Data any
  455. RawData []byte
  456. }
  457. func (m match) String() string {
  458. return fmt.Sprintf("{Name:%s, Data:%v}", m.Name, m.Data)
  459. }
  460. type matchTCP struct {
  461. SourcePortRange [2]uint16
  462. DestPortRange [2]uint16
  463. Option byte
  464. FlagMask byte
  465. FlagCompare byte
  466. InverseFlags byte
  467. }
  468. func (m matchTCP) String() string {
  469. var sb strings.Builder
  470. sb.WriteString("{")
  471. fmt.Fprintf(&sb, "SrcPort:%s, DstPort:%s",
  472. formatPortRange(m.SourcePortRange),
  473. formatPortRange(m.DestPortRange))
  474. // TODO(andrew): format semantically
  475. if m.Option != 0 {
  476. fmt.Fprintf(&sb, ", Option:%d", m.Option)
  477. }
  478. if m.FlagMask != 0 {
  479. fmt.Fprintf(&sb, ", FlagMask:%d", m.FlagMask)
  480. }
  481. if m.FlagCompare != 0 {
  482. fmt.Fprintf(&sb, ", FlagCompare:%d", m.FlagCompare)
  483. }
  484. if m.InverseFlags != 0 {
  485. fmt.Fprintf(&sb, ", InverseFlags:%d", m.InverseFlags)
  486. }
  487. sb.WriteString("}")
  488. return sb.String()
  489. }
  490. func (p *entryParser) parseMatches(maxOffset int) ([]match, error) {
  491. const XT_EXTENSION_MAXNAMELEN = 29
  492. const structSize = 2 + XT_EXTENSION_MAXNAMELEN + 1
  493. var ret []match
  494. for {
  495. // If we don't have space for a single match structure, we're done
  496. if p.offset+structSize > maxOffset {
  497. break
  498. }
  499. var curr match
  500. matchSize := int(native.Endian.Uint16(p.getBytes(2)))
  501. curr.Name = unix.ByteSliceToString(p.getBytes(XT_EXTENSION_MAXNAMELEN))
  502. curr.Revision = int(p.getByte())
  503. // The data size is the total match size minus what we've already consumed.
  504. dataLen := matchSize - structSize
  505. dataEnd := p.offset + dataLen
  506. // If we don't have space for the match data, then there's something wrong
  507. if dataEnd > maxOffset {
  508. return nil, fmt.Errorf("out of space for match (%d > max %d): %w", dataEnd, maxOffset, errMalformed)
  509. } else if dataEnd > len(p.buf) {
  510. return nil, fmt.Errorf("out of space for match (%d > buf %d): %w", dataEnd, len(p.buf), errMalformed)
  511. }
  512. curr.RawData = p.getBytes(dataLen)
  513. // TODO(andrew): more here; UDP, etc.
  514. switch curr.Name {
  515. case "tcp":
  516. /*
  517. struct xt_tcp {
  518. __u16 spts[2]; // Source port range.
  519. __u16 dpts[2]; // Destination port range.
  520. __u8 option; // TCP Option iff non-zero
  521. __u8 flg_mask; // TCP flags mask byte
  522. __u8 flg_cmp; // TCP flags compare byte
  523. __u8 invflags; // Inverse flags
  524. };
  525. */
  526. if len(curr.RawData) >= 12 {
  527. curr.Data = matchTCP{
  528. SourcePortRange: [...]uint16{
  529. native.Endian.Uint16(curr.RawData[0:2]),
  530. native.Endian.Uint16(curr.RawData[2:4]),
  531. },
  532. DestPortRange: [...]uint16{
  533. native.Endian.Uint16(curr.RawData[4:6]),
  534. native.Endian.Uint16(curr.RawData[6:8]),
  535. },
  536. Option: curr.RawData[8],
  537. FlagMask: curr.RawData[9],
  538. FlagCompare: curr.RawData[10],
  539. InverseFlags: curr.RawData[11],
  540. }
  541. }
  542. }
  543. ret = append(ret, curr)
  544. }
  545. return ret, nil
  546. }
  547. type target struct {
  548. Name string
  549. Revision int
  550. Data any
  551. RawData []byte
  552. }
  553. func (t target) String() string {
  554. return fmt.Sprintf("{Name:%s, Data:%v}", t.Name, t.Data)
  555. }
  556. func (p *entryParser) parseTarget(nextOffset int) (target, error) {
  557. const XT_EXTENSION_MAXNAMELEN = 29
  558. const structSize = 2 + XT_EXTENSION_MAXNAMELEN + 1
  559. if err := p.assertLen(structSize); err != nil {
  560. return target{}, err
  561. }
  562. var ret target
  563. targetSize := int(native.Endian.Uint16(p.getBytes(2)))
  564. ret.Name = unix.ByteSliceToString(p.getBytes(XT_EXTENSION_MAXNAMELEN))
  565. ret.Revision = int(p.getByte())
  566. if targetSize > structSize {
  567. dataLen := targetSize - structSize
  568. if err := p.assertLen(dataLen); err != nil {
  569. return target{}, err
  570. }
  571. ret.RawData = p.getBytes(dataLen)
  572. }
  573. // Special case; matches what iptables does
  574. if ret.Name == "" {
  575. ret.Name = "standard"
  576. }
  577. switch ret.Name {
  578. case "standard":
  579. if len(ret.RawData) >= 4 {
  580. verdict := int32(native.Endian.Uint32(ret.RawData))
  581. var info string
  582. switch verdict {
  583. case -1:
  584. info = "DROP"
  585. case -2:
  586. info = "ACCEPT"
  587. case -4:
  588. info = "QUEUE"
  589. case -5:
  590. info = "RETURN"
  591. case int32(nextOffset):
  592. info = "FALLTHROUGH"
  593. default:
  594. info = fmt.Sprintf("JUMP(%d)", verdict)
  595. }
  596. ret.Data = standardTarget{Verdict: info}
  597. }
  598. case "ERROR":
  599. ret.Data = errorTarget{
  600. ErrorName: unix.ByteSliceToString(ret.RawData),
  601. }
  602. case "REJECT":
  603. if len(ret.RawData) >= 4 {
  604. ret.Data = rejectTarget{
  605. With: rejectWith(native.Endian.Uint32(ret.RawData)),
  606. }
  607. }
  608. case "MARK":
  609. if len(ret.RawData) >= 8 {
  610. mark := native.Endian.Uint32(ret.RawData[0:4])
  611. mask := native.Endian.Uint32(ret.RawData[4:8])
  612. var mode markMode
  613. switch {
  614. case mark == 0:
  615. mode = markModeAnd
  616. mark = ^mask
  617. case mark == mask:
  618. mode = markModeOr
  619. case mask == 0:
  620. mode = markModeXor
  621. case mask == 0xffffffff:
  622. mode = markModeSet
  623. default:
  624. // TODO(andrew): handle xset?
  625. }
  626. ret.Data = markTarget{
  627. Mark: mark,
  628. Mode: mode,
  629. }
  630. }
  631. }
  632. return ret, nil
  633. }
  634. // Various types for things in iptables-land follow.
  635. type standardTarget struct {
  636. Verdict string
  637. }
  638. type errorTarget struct {
  639. ErrorName string
  640. }
  641. type rejectWith int
  642. const (
  643. rwIPT_ICMP_NET_UNREACHABLE rejectWith = iota
  644. rwIPT_ICMP_HOST_UNREACHABLE
  645. rwIPT_ICMP_PROT_UNREACHABLE
  646. rwIPT_ICMP_PORT_UNREACHABLE
  647. rwIPT_ICMP_ECHOREPLY
  648. rwIPT_ICMP_NET_PROHIBITED
  649. rwIPT_ICMP_HOST_PROHIBITED
  650. rwIPT_TCP_RESET
  651. rwIPT_ICMP_ADMIN_PROHIBITED
  652. )
  653. func (rw rejectWith) String() string {
  654. switch rw {
  655. case rwIPT_ICMP_NET_UNREACHABLE:
  656. return "icmp-net-unreachable"
  657. case rwIPT_ICMP_HOST_UNREACHABLE:
  658. return "icmp-host-unreachable"
  659. case rwIPT_ICMP_PROT_UNREACHABLE:
  660. return "icmp-prot-unreachable"
  661. case rwIPT_ICMP_PORT_UNREACHABLE:
  662. return "icmp-port-unreachable"
  663. case rwIPT_ICMP_ECHOREPLY:
  664. return "icmp-echo-reply"
  665. case rwIPT_ICMP_NET_PROHIBITED:
  666. return "icmp-net-prohibited"
  667. case rwIPT_ICMP_HOST_PROHIBITED:
  668. return "icmp-host-prohibited"
  669. case rwIPT_TCP_RESET:
  670. return "tcp-reset"
  671. case rwIPT_ICMP_ADMIN_PROHIBITED:
  672. return "icmp-admin-prohibited"
  673. default:
  674. return "UNKNOWN"
  675. }
  676. }
  677. type rejectTarget struct {
  678. With rejectWith
  679. }
  680. type markMode byte
  681. const (
  682. markModeSet markMode = iota
  683. markModeAnd
  684. markModeOr
  685. markModeXor
  686. )
  687. func (mm markMode) String() string {
  688. switch mm {
  689. case markModeSet:
  690. return "set"
  691. case markModeAnd:
  692. return "and"
  693. case markModeOr:
  694. return "or"
  695. case markModeXor:
  696. return "xor"
  697. default:
  698. return "UNKNOWN"
  699. }
  700. }
  701. type markTarget struct {
  702. Mode markMode
  703. Mark uint32
  704. }