conntrack_linux.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. package netlink
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "time"
  9. "github.com/vishvananda/netlink/nl"
  10. "golang.org/x/sys/unix"
  11. )
  12. // ConntrackTableType Conntrack table for the netlink operation
  13. type ConntrackTableType uint8
  14. const (
  15. // ConntrackTable Conntrack table
  16. // https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK 1
  17. ConntrackTable = 1
  18. // ConntrackExpectTable Conntrack expect table
  19. // https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2
  20. ConntrackExpectTable = 2
  21. )
  22. const (
  23. // backward compatibility with golang 1.6 which does not have io.SeekCurrent
  24. seekCurrent = 1
  25. )
  26. // InetFamily Family type
  27. type InetFamily uint8
  28. // -L [table] [options] List conntrack or expectation table
  29. // -G [table] parameters Get conntrack or expectation
  30. // -I [table] parameters Create a conntrack or expectation
  31. // -U [table] parameters Update a conntrack
  32. // -E [table] [options] Show events
  33. // -C [table] Show counter
  34. // -S Show statistics
  35. // ConntrackTableList returns the flow list of a table of a specific family
  36. // conntrack -L [table] [options] List conntrack or expectation table
  37. func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
  38. return pkgHandle.ConntrackTableList(table, family)
  39. }
  40. // ConntrackTableFlush flushes all the flows of a specified table
  41. // conntrack -F [table] Flush table
  42. // The flush operation applies to all the family types
  43. func ConntrackTableFlush(table ConntrackTableType) error {
  44. return pkgHandle.ConntrackTableFlush(table)
  45. }
  46. // ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
  47. // conntrack -D [table] parameters Delete conntrack or expectation
  48. func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter CustomConntrackFilter) (uint, error) {
  49. return pkgHandle.ConntrackDeleteFilter(table, family, filter)
  50. }
  51. // ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
  52. // conntrack -L [table] [options] List conntrack or expectation table
  53. func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
  54. res, err := h.dumpConntrackTable(table, family)
  55. if err != nil {
  56. return nil, err
  57. }
  58. // Deserialize all the flows
  59. var result []*ConntrackFlow
  60. for _, dataRaw := range res {
  61. result = append(result, parseRawData(dataRaw))
  62. }
  63. return result, nil
  64. }
  65. // ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
  66. // conntrack -F [table] Flush table
  67. // The flush operation applies to all the family types
  68. func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
  69. req := h.newConntrackRequest(table, unix.AF_INET, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
  70. _, err := req.Execute(unix.NETLINK_NETFILTER, 0)
  71. return err
  72. }
  73. // ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
  74. // conntrack -D [table] parameters Delete conntrack or expectation
  75. func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter CustomConntrackFilter) (uint, error) {
  76. res, err := h.dumpConntrackTable(table, family)
  77. if err != nil {
  78. return 0, err
  79. }
  80. var matched uint
  81. for _, dataRaw := range res {
  82. flow := parseRawData(dataRaw)
  83. if match := filter.MatchConntrackFlow(flow); match {
  84. req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
  85. // skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
  86. req2.AddRawData(dataRaw[4:])
  87. req2.Execute(unix.NETLINK_NETFILTER, 0)
  88. matched++
  89. }
  90. }
  91. return matched, nil
  92. }
  93. func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily, operation, flags int) *nl.NetlinkRequest {
  94. // Create the Netlink request object
  95. req := h.newNetlinkRequest((int(table)<<8)|operation, flags)
  96. // Add the netfilter header
  97. msg := &nl.Nfgenmsg{
  98. NfgenFamily: uint8(family),
  99. Version: nl.NFNETLINK_V0,
  100. ResId: 0,
  101. }
  102. req.AddData(msg)
  103. return req
  104. }
  105. func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
  106. req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, unix.NLM_F_DUMP)
  107. return req.Execute(unix.NETLINK_NETFILTER, 0)
  108. }
  109. // The full conntrack flow structure is very complicated and can be found in the file:
  110. // http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
  111. // For the time being, the structure below allows to parse and extract the base information of a flow
  112. type ipTuple struct {
  113. Bytes uint64
  114. DstIP net.IP
  115. DstPort uint16
  116. Packets uint64
  117. Protocol uint8
  118. SrcIP net.IP
  119. SrcPort uint16
  120. }
  121. type ConntrackFlow struct {
  122. FamilyType uint8
  123. Forward ipTuple
  124. Reverse ipTuple
  125. Mark uint32
  126. TimeStart uint64
  127. TimeStop uint64
  128. TimeOut uint32
  129. }
  130. func (s *ConntrackFlow) String() string {
  131. // conntrack cmd output:
  132. // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
  133. // start=2019-07-26 01:26:21.557800506 +0000 UTC stop=1970-01-01 00:00:00 +0000 UTC timeout=30(sec)
  134. start := time.Unix(0, int64(s.TimeStart))
  135. stop := time.Unix(0, int64(s.TimeStop))
  136. timeout := int32(s.TimeOut)
  137. return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=0x%x start=%v stop=%v timeout=%d(sec)",
  138. nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
  139. s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
  140. s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
  141. s.Mark, start, stop, timeout)
  142. }
  143. // This method parse the ip tuple structure
  144. // The message structure is the following:
  145. // <len, [CTA_IP_V4_SRC|CTA_IP_V6_SRC], 16 bytes for the IP>
  146. // <len, [CTA_IP_V4_DST|CTA_IP_V6_DST], 16 bytes for the IP>
  147. // <len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO, 1 byte for the protocol, 3 bytes of padding>
  148. // <len, CTA_PROTO_SRC_PORT, 2 bytes for the source port, 2 bytes of padding>
  149. // <len, CTA_PROTO_DST_PORT, 2 bytes for the source port, 2 bytes of padding>
  150. func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) uint8 {
  151. for i := 0; i < 2; i++ {
  152. _, t, _, v := parseNfAttrTLV(reader)
  153. switch t {
  154. case nl.CTA_IP_V4_SRC, nl.CTA_IP_V6_SRC:
  155. tpl.SrcIP = v
  156. case nl.CTA_IP_V4_DST, nl.CTA_IP_V6_DST:
  157. tpl.DstIP = v
  158. }
  159. }
  160. // Get total length of nested protocol-specific info.
  161. _, _, protoInfoTotalLen := parseNfAttrTL(reader)
  162. _, t, l, v := parseNfAttrTLV(reader)
  163. // Track the number of bytes read.
  164. protoInfoBytesRead := uint16(nl.SizeofNfattr) + l
  165. if t == nl.CTA_PROTO_NUM {
  166. tpl.Protocol = uint8(v[0])
  167. }
  168. // We only parse TCP & UDP headers. Skip the others.
  169. if tpl.Protocol != 6 && tpl.Protocol != 17 {
  170. // skip the rest
  171. bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
  172. reader.Seek(int64(bytesRemaining), seekCurrent)
  173. return tpl.Protocol
  174. }
  175. // Skip 3 bytes of padding
  176. reader.Seek(3, seekCurrent)
  177. protoInfoBytesRead += 3
  178. for i := 0; i < 2; i++ {
  179. _, t, _ := parseNfAttrTL(reader)
  180. protoInfoBytesRead += uint16(nl.SizeofNfattr)
  181. switch t {
  182. case nl.CTA_PROTO_SRC_PORT:
  183. parseBERaw16(reader, &tpl.SrcPort)
  184. protoInfoBytesRead += 2
  185. case nl.CTA_PROTO_DST_PORT:
  186. parseBERaw16(reader, &tpl.DstPort)
  187. protoInfoBytesRead += 2
  188. }
  189. // Skip 2 bytes of padding
  190. reader.Seek(2, seekCurrent)
  191. protoInfoBytesRead += 2
  192. }
  193. // Skip any remaining/unknown parts of the message
  194. bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
  195. reader.Seek(int64(bytesRemaining), seekCurrent)
  196. return tpl.Protocol
  197. }
  198. func parseNfAttrTLV(r *bytes.Reader) (isNested bool, attrType, len uint16, value []byte) {
  199. isNested, attrType, len = parseNfAttrTL(r)
  200. value = make([]byte, len)
  201. binary.Read(r, binary.BigEndian, &value)
  202. return isNested, attrType, len, value
  203. }
  204. func parseNfAttrTL(r *bytes.Reader) (isNested bool, attrType, len uint16) {
  205. binary.Read(r, nl.NativeEndian(), &len)
  206. len -= nl.SizeofNfattr
  207. binary.Read(r, nl.NativeEndian(), &attrType)
  208. isNested = (attrType & nl.NLA_F_NESTED) == nl.NLA_F_NESTED
  209. attrType = attrType & (nl.NLA_F_NESTED - 1)
  210. return isNested, attrType, len
  211. }
  212. func skipNfAttrValue(r *bytes.Reader, len uint16) {
  213. len = (len + nl.NLA_ALIGNTO - 1) & ^(nl.NLA_ALIGNTO - 1)
  214. r.Seek(int64(len), seekCurrent)
  215. }
  216. func parseBERaw16(r *bytes.Reader, v *uint16) {
  217. binary.Read(r, binary.BigEndian, v)
  218. }
  219. func parseBERaw32(r *bytes.Reader, v *uint32) {
  220. binary.Read(r, binary.BigEndian, v)
  221. }
  222. func parseBERaw64(r *bytes.Reader, v *uint64) {
  223. binary.Read(r, binary.BigEndian, v)
  224. }
  225. func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
  226. for i := 0; i < 2; i++ {
  227. switch _, t, _ := parseNfAttrTL(r); t {
  228. case nl.CTA_COUNTERS_BYTES:
  229. parseBERaw64(r, &bytes)
  230. case nl.CTA_COUNTERS_PACKETS:
  231. parseBERaw64(r, &packets)
  232. default:
  233. return
  234. }
  235. }
  236. return
  237. }
  238. // when the flow is alive, only the timestamp_start is returned in structure
  239. func parseTimeStamp(r *bytes.Reader, readSize uint16) (tstart, tstop uint64) {
  240. var numTimeStamps int
  241. oneItem := nl.SizeofNfattr + 8 // 4 bytes attr header + 8 bytes timestamp
  242. if readSize == uint16(oneItem) {
  243. numTimeStamps = 1
  244. } else if readSize == 2*uint16(oneItem) {
  245. numTimeStamps = 2
  246. } else {
  247. return
  248. }
  249. for i := 0; i < numTimeStamps; i++ {
  250. switch _, t, _ := parseNfAttrTL(r); t {
  251. case nl.CTA_TIMESTAMP_START:
  252. parseBERaw64(r, &tstart)
  253. case nl.CTA_TIMESTAMP_STOP:
  254. parseBERaw64(r, &tstop)
  255. default:
  256. return
  257. }
  258. }
  259. return
  260. }
  261. func parseTimeOut(r *bytes.Reader) (ttimeout uint32) {
  262. parseBERaw32(r, &ttimeout)
  263. return
  264. }
  265. func parseConnectionMark(r *bytes.Reader) (mark uint32) {
  266. parseBERaw32(r, &mark)
  267. return
  268. }
  269. func parseRawData(data []byte) *ConntrackFlow {
  270. s := &ConntrackFlow{}
  271. // First there is the Nfgenmsg header
  272. // consume only the family field
  273. reader := bytes.NewReader(data)
  274. binary.Read(reader, nl.NativeEndian(), &s.FamilyType)
  275. // skip rest of the Netfilter header
  276. reader.Seek(3, seekCurrent)
  277. // The message structure is the following:
  278. // <len, NLA_F_NESTED|CTA_TUPLE_ORIG> 4 bytes
  279. // <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
  280. // flow information of the forward flow
  281. // <len, NLA_F_NESTED|CTA_TUPLE_REPLY> 4 bytes
  282. // <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
  283. // flow information of the reverse flow
  284. for reader.Len() > 0 {
  285. if nested, t, l := parseNfAttrTL(reader); nested {
  286. switch t {
  287. case nl.CTA_TUPLE_ORIG:
  288. if nested, t, l = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
  289. parseIpTuple(reader, &s.Forward)
  290. }
  291. case nl.CTA_TUPLE_REPLY:
  292. if nested, t, l = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
  293. parseIpTuple(reader, &s.Reverse)
  294. } else {
  295. // Header not recognized skip it
  296. skipNfAttrValue(reader, l)
  297. }
  298. case nl.CTA_COUNTERS_ORIG:
  299. s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader)
  300. case nl.CTA_COUNTERS_REPLY:
  301. s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader)
  302. case nl.CTA_TIMESTAMP:
  303. s.TimeStart, s.TimeStop = parseTimeStamp(reader, l)
  304. case nl.CTA_PROTOINFO:
  305. skipNfAttrValue(reader, l)
  306. default:
  307. skipNfAttrValue(reader, l)
  308. }
  309. } else {
  310. switch t {
  311. case nl.CTA_MARK:
  312. s.Mark = parseConnectionMark(reader)
  313. case nl.CTA_TIMEOUT:
  314. s.TimeOut = parseTimeOut(reader)
  315. case nl.CTA_STATUS, nl.CTA_USE, nl.CTA_ID:
  316. skipNfAttrValue(reader, l)
  317. default:
  318. skipNfAttrValue(reader, l)
  319. }
  320. }
  321. }
  322. return s
  323. }
  324. // Conntrack parameters and options:
  325. // -n, --src-nat ip source NAT ip
  326. // -g, --dst-nat ip destination NAT ip
  327. // -j, --any-nat ip source or destination NAT ip
  328. // -m, --mark mark Set mark
  329. // -c, --secmark secmark Set selinux secmark
  330. // -e, --event-mask eventmask Event mask, eg. NEW,DESTROY
  331. // -z, --zero Zero counters while listing
  332. // -o, --output type[,...] Output format, eg. xml
  333. // -l, --label label[,...] conntrack labels
  334. // Common parameters and options:
  335. // -s, --src, --orig-src ip Source address from original direction
  336. // -d, --dst, --orig-dst ip Destination address from original direction
  337. // -r, --reply-src ip Source address from reply direction
  338. // -q, --reply-dst ip Destination address from reply direction
  339. // -p, --protonum proto Layer 4 Protocol, eg. 'tcp'
  340. // -f, --family proto Layer 3 Protocol, eg. 'ipv6'
  341. // -t, --timeout timeout Set timeout
  342. // -u, --status status Set status, eg. ASSURED
  343. // -w, --zone value Set conntrack zone
  344. // --orig-zone value Set zone for original direction
  345. // --reply-zone value Set zone for reply direction
  346. // -b, --buffer-size Netlink socket buffer size
  347. // --mask-src ip Source mask address
  348. // --mask-dst ip Destination mask address
  349. // Layer 4 Protocol common parameters and options:
  350. // TCP, UDP, SCTP, UDPLite and DCCP
  351. // --sport, --orig-port-src port Source port in original direction
  352. // --dport, --orig-port-dst port Destination port in original direction
  353. // Filter types
  354. type ConntrackFilterType uint8
  355. const (
  356. ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
  357. ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
  358. ConntrackReplySrcIP // --reply-src ip Reply Source IP
  359. ConntrackReplyDstIP // --reply-dst ip Reply Destination IP
  360. ConntrackReplyAnyIP // Match source or destination reply IP
  361. ConntrackOrigSrcPort // --orig-port-src port Source port in original direction
  362. ConntrackOrigDstPort // --orig-port-dst port Destination port in original direction
  363. ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
  364. ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
  365. ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instead ConntrackReplyAnyIP
  366. )
  367. type CustomConntrackFilter interface {
  368. // MatchConntrackFlow applies the filter to the flow and returns true if the flow matches
  369. // the filter or false otherwise
  370. MatchConntrackFlow(flow *ConntrackFlow) bool
  371. }
  372. type ConntrackFilter struct {
  373. ipNetFilter map[ConntrackFilterType]*net.IPNet
  374. portFilter map[ConntrackFilterType]uint16
  375. protoFilter uint8
  376. }
  377. // AddIPNet adds a IP subnet to the conntrack filter
  378. func (f *ConntrackFilter) AddIPNet(tp ConntrackFilterType, ipNet *net.IPNet) error {
  379. if ipNet == nil {
  380. return fmt.Errorf("Filter attribute empty")
  381. }
  382. if f.ipNetFilter == nil {
  383. f.ipNetFilter = make(map[ConntrackFilterType]*net.IPNet)
  384. }
  385. if _, ok := f.ipNetFilter[tp]; ok {
  386. return errors.New("Filter attribute already present")
  387. }
  388. f.ipNetFilter[tp] = ipNet
  389. return nil
  390. }
  391. // AddIP adds an IP to the conntrack filter
  392. func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
  393. if ip == nil {
  394. return fmt.Errorf("Filter attribute empty")
  395. }
  396. return f.AddIPNet(tp, NewIPNet(ip))
  397. }
  398. // AddPort adds a Port to the conntrack filter if the Layer 4 protocol allows it
  399. func (f *ConntrackFilter) AddPort(tp ConntrackFilterType, port uint16) error {
  400. switch f.protoFilter {
  401. // TCP, UDP, DCCP, SCTP, UDPLite
  402. case 6, 17, 33, 132, 136:
  403. default:
  404. return fmt.Errorf("Filter attribute not available without a valid Layer 4 protocol: %d", f.protoFilter)
  405. }
  406. if f.portFilter == nil {
  407. f.portFilter = make(map[ConntrackFilterType]uint16)
  408. }
  409. if _, ok := f.portFilter[tp]; ok {
  410. return errors.New("Filter attribute already present")
  411. }
  412. f.portFilter[tp] = port
  413. return nil
  414. }
  415. // AddProtocol adds the Layer 4 protocol to the conntrack filter
  416. func (f *ConntrackFilter) AddProtocol(proto uint8) error {
  417. if f.protoFilter != 0 {
  418. return errors.New("Filter attribute already present")
  419. }
  420. f.protoFilter = proto
  421. return nil
  422. }
  423. // MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
  424. // false otherwise
  425. func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
  426. if len(f.ipNetFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 {
  427. // empty filter always not match
  428. return false
  429. }
  430. // -p, --protonum proto Layer 4 Protocol, eg. 'tcp'
  431. if f.protoFilter != 0 && flow.Forward.Protocol != f.protoFilter {
  432. // different Layer 4 protocol always not match
  433. return false
  434. }
  435. match := true
  436. // IP conntrack filter
  437. if len(f.ipNetFilter) > 0 {
  438. // -orig-src ip Source address from original direction
  439. if elem, found := f.ipNetFilter[ConntrackOrigSrcIP]; found {
  440. match = match && elem.Contains(flow.Forward.SrcIP)
  441. }
  442. // -orig-dst ip Destination address from original direction
  443. if elem, found := f.ipNetFilter[ConntrackOrigDstIP]; match && found {
  444. match = match && elem.Contains(flow.Forward.DstIP)
  445. }
  446. // -src-nat ip Source NAT ip
  447. if elem, found := f.ipNetFilter[ConntrackReplySrcIP]; match && found {
  448. match = match && elem.Contains(flow.Reverse.SrcIP)
  449. }
  450. // -dst-nat ip Destination NAT ip
  451. if elem, found := f.ipNetFilter[ConntrackReplyDstIP]; match && found {
  452. match = match && elem.Contains(flow.Reverse.DstIP)
  453. }
  454. // Match source or destination reply IP
  455. if elem, found := f.ipNetFilter[ConntrackReplyAnyIP]; match && found {
  456. match = match && (elem.Contains(flow.Reverse.SrcIP) || elem.Contains(flow.Reverse.DstIP))
  457. }
  458. }
  459. // Layer 4 Port filter
  460. if len(f.portFilter) > 0 {
  461. // -orig-port-src port Source port from original direction
  462. if elem, found := f.portFilter[ConntrackOrigSrcPort]; match && found {
  463. match = match && elem == flow.Forward.SrcPort
  464. }
  465. // -orig-port-dst port Destination port from original direction
  466. if elem, found := f.portFilter[ConntrackOrigDstPort]; match && found {
  467. match = match && elem == flow.Forward.DstPort
  468. }
  469. }
  470. return match
  471. }
  472. var _ CustomConntrackFilter = (*ConntrackFilter)(nil)