conntrack.go 3.7 KB

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