From e621be3c9948876cde01cb5aeceb201f9779a276 Mon Sep 17 00:00:00 2001 From: Hongliang Liu <75655411+hongliangl@users.noreply.github.com> Date: Tue, 28 May 2024 22:48:33 +0800 Subject: [PATCH] Update iptables builder This PR adds more methods to build an iptables entries: - `SetTargetDNATToDst`, setting DNAT destination IP and port. This PR also updates the methods: - `MatchCIDRSrc`, supporting an IP or CIDR as source. - `MatchCIDRDst`, supporting an IP or CIDR as destination. - `MatchIPSetSrc`, supporting ipset type of hashIPPort as destination IP and port. - `MatchIPSetDst`, supporting ipset type of hashIPPort as source IP and port. - Rename `MatchDstPort` to `MatchPortDst` to be consistent with other method. - Rename `MatchSrcPort` to `MatchPortSrc` to be consistent with other method. Signed-off-by: Hongliang Liu --- .../networkpolicy/node_reconciler_linux.go | 15 +++--- pkg/agent/util/iptables/builder.go | 51 ++++++++++++++++--- pkg/agent/util/iptables/builder_test.go | 28 +++++++--- pkg/agent/util/iptables/iptables.go | 11 ++-- 4 files changed, 81 insertions(+), 24 deletions(-) diff --git a/pkg/agent/controller/networkpolicy/node_reconciler_linux.go b/pkg/agent/controller/networkpolicy/node_reconciler_linux.go index dba3bb55bff..f3c2d3982ee 100644 --- a/pkg/agent/controller/networkpolicy/node_reconciler_linux.go +++ b/pkg/agent/controller/networkpolicy/node_reconciler_linux.go @@ -31,6 +31,7 @@ import ( "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/agent/route" "antrea.io/antrea/pkg/agent/types" + "antrea.io/antrea/pkg/agent/util/ipset" "antrea.io/antrea/pkg/agent/util/iptables" "antrea.io/antrea/pkg/apis/controlplane/v1beta2" secv1beta1 "antrea.io/antrea/pkg/apis/crd/v1beta1" @@ -42,6 +43,8 @@ const ( ipv6Any = "::/0" ) +var ipsetTypeHashIP = ipset.HashIP + /* Tips: In the following, service describes a port to allow traffic on which is defined in pkg/apis/controlplane/v1beta2/types.go @@ -622,7 +625,7 @@ func buildCoreIPTRule(ipProtocol iptables.Protocol, builder := iptables.NewRuleBuilder(iptChain) if isIngress { if ipset != "" { - builder = builder.MatchIPSetSrc(ipset) + builder = builder.MatchIPSetSrc(ipset, ipsetTypeHashIP) } else if ipnet != "" { builder = builder.MatchCIDRSrc(ipnet) } else { @@ -631,7 +634,7 @@ func buildCoreIPTRule(ipProtocol iptables.Protocol, } } else { if ipset != "" { - builder = builder.MatchIPSetDst(ipset) + builder = builder.MatchIPSetDst(ipset, ipsetTypeHashIP) } else if ipnet != "" { builder = builder.MatchCIDRDst(ipnet) } else { @@ -648,8 +651,8 @@ func buildCoreIPTRule(ipProtocol iptables.Protocol, fallthrough case "sctp": builder = builder.MatchTransProtocol(transProtocol). - MatchSrcPort(service.SrcPort, service.SrcEndPort). - MatchDstPort(service.Port, service.EndPort) + MatchPortSrc(service.SrcPort, service.SrcEndPort). + MatchPortDst(service.Port, service.EndPort) case "icmp": builder = builder.MatchICMP(service.ICMPType, service.ICMPCode, ipProtocol) } @@ -673,8 +676,8 @@ func buildServiceIPTRules(ipProtocol iptables.Protocol, services []v1beta2.Servi fallthrough case "sctp": copiedBuilder = copiedBuilder.MatchTransProtocol(transProtocol). - MatchSrcPort(svc.SrcPort, svc.SrcEndPort). - MatchDstPort(svc.Port, svc.EndPort) + MatchPortSrc(svc.SrcPort, svc.SrcEndPort). + MatchPortDst(svc.Port, svc.EndPort) case "icmp": copiedBuilder = copiedBuilder.MatchICMP(svc.ICMPType, svc.ICMPCode, ipProtocol) } diff --git a/pkg/agent/util/iptables/builder.go b/pkg/agent/util/iptables/builder.go index c0dcad4dd7e..f247ed5d250 100644 --- a/pkg/agent/util/iptables/builder.go +++ b/pkg/agent/util/iptables/builder.go @@ -23,6 +23,8 @@ import ( "strings" "k8s.io/apimachinery/pkg/util/intstr" + + "antrea.io/antrea/pkg/agent/util/ipset" ) type iptablesRule struct { @@ -67,20 +69,38 @@ func (b *iptablesRuleBuilder) MatchCIDRDst(cidr string) IPTablesRuleBuilder { return b } -func (b *iptablesRuleBuilder) MatchIPSetSrc(ipset string) IPTablesRuleBuilder { - if ipset == "" { +func (b *iptablesRuleBuilder) MatchIPSetSrc(ipsetName string, ipsetType ipset.SetType) IPTablesRuleBuilder { + if ipsetName == "" { return b } - matchStr := fmt.Sprintf("-m set --match-set %s src", ipset) + var typeStr string + switch ipsetType { + case ipset.HashNet: + fallthrough + case ipset.HashIP: + typeStr = "src" + case ipset.HashIPPort: + typeStr = "src,src" + } + matchStr := fmt.Sprintf("-m set --match-set %s %s", ipsetName, typeStr) b.writeSpec(matchStr) return b } -func (b *iptablesRuleBuilder) MatchIPSetDst(ipset string) IPTablesRuleBuilder { - if ipset == "" { +func (b *iptablesRuleBuilder) MatchIPSetDst(ipsetName string, ipsetType ipset.SetType) IPTablesRuleBuilder { + if ipsetName == "" { return b } - matchStr := fmt.Sprintf("-m set --match-set %s dst", ipset) + var typeStr string + switch ipsetType { + case ipset.HashNet: + fallthrough + case ipset.HashIP: + typeStr = "dst" + case ipset.HashIPPort: + typeStr = "dst,dst" + } + matchStr := fmt.Sprintf("-m set --match-set %s %s", ipsetName, typeStr) b.writeSpec(matchStr) return b } @@ -94,7 +114,7 @@ func (b *iptablesRuleBuilder) MatchTransProtocol(protocol string) IPTablesRuleBu return b } -func (b *iptablesRuleBuilder) MatchDstPort(port *intstr.IntOrString, endPort *int32) IPTablesRuleBuilder { +func (b *iptablesRuleBuilder) MatchPortDst(port *intstr.IntOrString, endPort *int32) IPTablesRuleBuilder { if port == nil { return b } @@ -108,7 +128,7 @@ func (b *iptablesRuleBuilder) MatchDstPort(port *intstr.IntOrString, endPort *in return b } -func (b *iptablesRuleBuilder) MatchSrcPort(port, endPort *int32) IPTablesRuleBuilder { +func (b *iptablesRuleBuilder) MatchPortSrc(port, endPort *int32) IPTablesRuleBuilder { if port == nil { return b } @@ -178,6 +198,21 @@ func (b *iptablesRuleBuilder) SetTarget(target string) IPTablesRuleBuilder { return b } +func (b *iptablesRuleBuilder) SetTargetDNATToDst(dnatIP string, dnatPort *int32) IPTablesRuleBuilder { + if dnatIP == "" { + return b + } + var dstStr string + if dnatPort != nil { + dstStr = fmt.Sprintf("%s:%d", dnatIP, *dnatPort) + } else { + dstStr = dnatIP + } + specStr := fmt.Sprintf("--to-destination %s", dstStr) + b.writeSpec(specStr) + return b +} + func (b *iptablesRuleBuilder) SetComment(comment string) IPTablesRuleBuilder { if comment == "" { return b diff --git a/pkg/agent/util/iptables/builder_test.go b/pkg/agent/util/iptables/builder_test.go index c3da571a9a9..c03fc94d949 100644 --- a/pkg/agent/util/iptables/builder_test.go +++ b/pkg/agent/util/iptables/builder_test.go @@ -22,6 +22,8 @@ import ( "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/util/intstr" + + "antrea.io/antrea/pkg/agent/util/ipset" ) var ( @@ -50,11 +52,11 @@ func TestBuilders(t *testing.T) { name: "Accept TCP destination 8080 in FORWARD", chain: ForwardChain, buildFunc: func(builder IPTablesRuleBuilder) IPTablesRule { - return builder.MatchIPSetSrc(ipsetAlfa). - MatchIPSetDst(ipsetBravo). + return builder.MatchIPSetSrc(ipsetAlfa, ipset.HashIP). + MatchIPSetDst(ipsetBravo, ipset.HashIP). MatchInputInterface(eth0). MatchTransProtocol(ProtocolTCP). - MatchDstPort(port8080, nil). + MatchPortDst(port8080, nil). MatchCIDRSrc(cidr). SetComment("Accept TCP 8080"). SetTarget(AcceptTarget). @@ -66,10 +68,10 @@ func TestBuilders(t *testing.T) { name: "Drop UDP destination 137-139 in INPUT", chain: "INPUT", buildFunc: func(builder IPTablesRuleBuilder) IPTablesRule { - return builder.MatchIPSetSrc(ipsetAlfa). + return builder.MatchIPSetSrc(ipsetAlfa, ipset.HashIP). MatchInputInterface(eth0). MatchTransProtocol(ProtocolUDP). - MatchDstPort(port137, &port139). + MatchPortDst(port137, &port139). MatchCIDRDst(cidr). SetComment("Drop UDP 137-139"). SetTarget(DropTarget). @@ -83,7 +85,7 @@ func TestBuilders(t *testing.T) { buildFunc: func(builder IPTablesRuleBuilder) IPTablesRule { return builder.MatchOutputInterface(eth1). MatchTransProtocol(ProtocolSCTP). - MatchSrcPort(&port40000, &port50000). + MatchPortSrc(&port40000, &port50000). SetComment("Drop SCTP 40000-50000"). SetTarget(DropTarget). Done() @@ -123,6 +125,20 @@ func TestBuilders(t *testing.T) { }, expected: `-A INPUT -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT`, }, + { + name: "DNAT packets from specific connections", + chain: PreRoutingChain, + buildFunc: func(builder IPTablesRuleBuilder) IPTablesRule { + return builder.MatchCIDRSrc("192.168.77.100"). + MatchCIDRDst("10.96.0.10"). + MatchTransProtocol(ProtocolTCP). + MatchPortDst(port8080, nil). + SetTarget(DNATTarget). + SetTargetDNATToDst("10.10.0.2", &port40000). + Done() + }, + expected: `-A PREROUTING -s 192.168.77.100 -d 10.96.0.10 -p tcp --dport 8080 -j DNAT --to-destination 10.10.0.2:40000`, + }, } for _, tc := range testCases { diff --git a/pkg/agent/util/iptables/iptables.go b/pkg/agent/util/iptables/iptables.go index d436f80afbd..3025db1bbbd 100644 --- a/pkg/agent/util/iptables/iptables.go +++ b/pkg/agent/util/iptables/iptables.go @@ -28,6 +28,8 @@ import ( "github.com/coreos/go-iptables/iptables" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" + + "antrea.io/antrea/pkg/agent/util/ipset" ) const ( @@ -109,16 +111,17 @@ type Interface interface { type IPTablesRuleBuilder interface { MatchCIDRSrc(cidr string) IPTablesRuleBuilder MatchCIDRDst(cidr string) IPTablesRuleBuilder - MatchIPSetSrc(ipset string) IPTablesRuleBuilder - MatchIPSetDst(ipset string) IPTablesRuleBuilder + MatchIPSetSrc(ipset string, ipsetType ipset.SetType) IPTablesRuleBuilder + MatchIPSetDst(ipset string, ipsetType ipset.SetType) IPTablesRuleBuilder MatchTransProtocol(protocol string) IPTablesRuleBuilder - MatchDstPort(port *intstr.IntOrString, endPort *int32) IPTablesRuleBuilder - MatchSrcPort(port, endPort *int32) IPTablesRuleBuilder + MatchPortDst(port *intstr.IntOrString, endPort *int32) IPTablesRuleBuilder + MatchPortSrc(port, endPort *int32) IPTablesRuleBuilder MatchICMP(icmpType, icmpCode *int32, ipProtocol Protocol) IPTablesRuleBuilder MatchEstablishedOrRelated() IPTablesRuleBuilder MatchInputInterface(interfaceName string) IPTablesRuleBuilder MatchOutputInterface(interfaceName string) IPTablesRuleBuilder SetTarget(target string) IPTablesRuleBuilder + SetTargetDNATToDst(dnatIP string, dnatPort *int32) IPTablesRuleBuilder SetComment(comment string) IPTablesRuleBuilder CopyBuilder() IPTablesRuleBuilder Done() IPTablesRule