conntrack.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //go:build linux
  2. package iptables
  3. import (
  4. "context"
  5. "errors"
  6. "net"
  7. "syscall"
  8. "github.com/containerd/log"
  9. "github.com/docker/docker/libnetwork/types"
  10. "github.com/vishvananda/netlink"
  11. )
  12. // checkConntrackProgrammable checks if the handle supports the
  13. // NETLINK_NETFILTER and the base modules are loaded.
  14. func checkConntrackProgrammable(nlh *netlink.Handle) error {
  15. if !nlh.SupportsNetlinkFamily(syscall.NETLINK_NETFILTER) {
  16. return errors.New("conntrack is not available")
  17. }
  18. return nil
  19. }
  20. // DeleteConntrackEntries deletes all the conntrack connections on the host for the specified IP
  21. // Returns the number of flows deleted for IPv4, IPv6 else error
  22. func DeleteConntrackEntries(nlh *netlink.Handle, ipv4List []net.IP, ipv6List []net.IP) error {
  23. if err := checkConntrackProgrammable(nlh); err != nil {
  24. return err
  25. }
  26. var totalIPv4FlowPurged uint
  27. for _, ipAddress := range ipv4List {
  28. flowPurged, err := purgeConntrackState(nlh, syscall.AF_INET, ipAddress)
  29. if err != nil {
  30. log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s: %v", ipAddress, err)
  31. continue
  32. }
  33. totalIPv4FlowPurged += flowPurged
  34. }
  35. var totalIPv6FlowPurged uint
  36. for _, ipAddress := range ipv6List {
  37. flowPurged, err := purgeConntrackState(nlh, syscall.AF_INET6, ipAddress)
  38. if err != nil {
  39. log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s: %v", ipAddress, err)
  40. continue
  41. }
  42. totalIPv6FlowPurged += flowPurged
  43. }
  44. if totalIPv4FlowPurged > 0 || totalIPv6FlowPurged > 0 {
  45. log.G(context.TODO()).Debugf("DeleteConntrackEntries purged ipv4:%d, ipv6:%d", totalIPv4FlowPurged, totalIPv6FlowPurged)
  46. }
  47. return nil
  48. }
  49. func DeleteConntrackEntriesByPort(nlh *netlink.Handle, proto types.Protocol, ports []uint16) error {
  50. if err := checkConntrackProgrammable(nlh); err != nil {
  51. return err
  52. }
  53. var totalIPv4FlowPurged uint
  54. var totalIPv6FlowPurged uint
  55. for _, port := range ports {
  56. filter := &netlink.ConntrackFilter{}
  57. if err := filter.AddProtocol(uint8(proto)); err != nil {
  58. log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s port %d: %v", proto.String(), port, err)
  59. continue
  60. }
  61. if err := filter.AddPort(netlink.ConntrackOrigDstPort, port); err != nil {
  62. log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s port %d: %v", proto.String(), port, err)
  63. continue
  64. }
  65. v4FlowPurged, err := nlh.ConntrackDeleteFilter(netlink.ConntrackTable, syscall.AF_INET, filter)
  66. if err != nil {
  67. log.G(context.TODO()).Warnf("Failed to delete conntrack state for IPv4 %s port %d: %v", proto.String(), port, err)
  68. }
  69. totalIPv4FlowPurged += v4FlowPurged
  70. v6FlowPurged, err := nlh.ConntrackDeleteFilter(netlink.ConntrackTable, syscall.AF_INET6, filter)
  71. if err != nil {
  72. log.G(context.TODO()).Warnf("Failed to delete conntrack state for IPv6 %s port %d: %v", proto.String(), port, err)
  73. }
  74. totalIPv6FlowPurged += v6FlowPurged
  75. }
  76. if totalIPv4FlowPurged > 0 || totalIPv6FlowPurged > 0 {
  77. log.G(context.TODO()).Debugf("DeleteConntrackEntriesByPort for %s ports purged ipv4:%d, ipv6:%d", proto.String(), totalIPv4FlowPurged, totalIPv6FlowPurged)
  78. }
  79. return nil
  80. }
  81. func purgeConntrackState(nlh *netlink.Handle, family netlink.InetFamily, ipAddress net.IP) (uint, error) {
  82. filter := &netlink.ConntrackFilter{}
  83. // NOTE: doing the flush using the ipAddress is safe because today there cannot be multiple networks with the same subnet
  84. // so it will not be possible to flush flows that are of other containers
  85. if err := filter.AddIP(netlink.ConntrackNatAnyIP, ipAddress); err != nil {
  86. return 0, err
  87. }
  88. return nlh.ConntrackDeleteFilter(netlink.ConntrackTable, family, filter)
  89. }