diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index e57e5901dcf..8e73e9e45b1 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -1648,6 +1648,14 @@ func (proxier *Proxier) syncProxyRules() { // according to proxier.ipsetList information and the ipset match relationship that `ipsetWithIptablesChain` specified. // some ipset(kubeClusterIPSet for example) have particular match rules and iptables jump relation should be sync separately. func (proxier *Proxier) writeIptablesRules() { + + // Dismiss connects to localhost early in the service chain + loAddr := "127.0.0.0/8" + if proxier.ipFamily == v1.IPv6Protocol { + loAddr = "::1/128" + } + proxier.natRules.Write("-A", string(kubeServicesChain), "-s", loAddr, "-j", "RETURN") + // We are creating those slices ones here to avoid memory reallocations // in every loop. Note that reuse the memory, instead of doing: // slice = diff --git a/pkg/proxy/ipvs/proxier_test.go b/pkg/proxy/ipvs/proxier_test.go index 30f87d39432..d8974eb5d40 100644 --- a/pkg/proxy/ipvs/proxier_test.go +++ b/pkg/proxy/ipvs/proxier_test.go @@ -670,6 +670,8 @@ func TestNodePortIPv4(t *testing.T) { JumpChain: "ACCEPT", MatchSet: kubeHealthCheckNodePortSet, }}, string(kubeServicesChain): {{ + JumpChain: "RETURN", SourceAddress: "127.0.0.0/8", + }, { JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet, }, { JumpChain: string(kubeNodePortChain), MatchSet: "", @@ -2052,6 +2054,8 @@ func TestLoadBalancer(t *testing.T) { // Check iptables chain and rules epIpt := netlinktest.ExpectedIptablesChain{ string(kubeServicesChain): {{ + JumpChain: "RETURN", SourceAddress: "127.0.0.0/8", + }, { JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet, }, { JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet, @@ -2152,6 +2156,8 @@ func TestOnlyLocalNodePorts(t *testing.T) { // Check iptables chain and rules epIpt := netlinktest.ExpectedIptablesChain{ string(kubeServicesChain): {{ + JumpChain: "RETURN", SourceAddress: "127.0.0.0/8", + }, { JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet, }, { JumpChain: string(kubeNodePortChain), MatchSet: "", @@ -2324,6 +2330,8 @@ func TestLoadBalancerSourceRanges(t *testing.T) { // Check iptables chain and rules epIpt := netlinktest.ExpectedIptablesChain{ string(kubeServicesChain): {{ + JumpChain: "RETURN", SourceAddress: "127.0.0.0/8", + }, { JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet, }, { JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet, @@ -2403,6 +2411,7 @@ func TestAcceptIPVSTraffic(t *testing.T) { // Check iptables chain and rules epIpt := netlinktest.ExpectedIptablesChain{ string(kubeServicesChain): { + {JumpChain: "RETURN", SourceAddress: "127.0.0.0/8"}, {JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet}, {JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet}, {JumpChain: string(kubeMarkMasqChain), MatchSet: kubeExternalIPSet}, @@ -2501,6 +2510,8 @@ func TestOnlyLocalLoadBalancing(t *testing.T) { // Check iptables chain and rules epIpt := netlinktest.ExpectedIptablesChain{ string(kubeServicesChain): {{ + JumpChain: "RETURN", SourceAddress: "127.0.0.0/8", + }, { JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet, }, { JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet, @@ -6089,3 +6100,44 @@ func TestNoEndpointsMetric(t *testing.T) { } } } + +func TestDismissLocalhostRuleExist(t *testing.T) { + tests := []struct { + name string + ipFamily v1.IPFamily + src string + }{ + { + name: "ipv4 rule", + ipFamily: v1.IPv4Protocol, + src: "127.0.0.0/8", + }, + { + name: "ipv6 rule", + ipFamily: v1.IPv6Protocol, + src: "::1/128", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ipt := iptablestest.NewFake() + if test.ipFamily == v1.IPv6Protocol { + ipt = iptablestest.NewIPv6Fake() + } + ipvs := ipvstest.NewFake() + ipset := ipsettest.NewFake(testIPSetVersion) + fp := NewFakeProxier(ipt, ipvs, ipset, nil, nil, test.ipFamily) + + fp.syncProxyRules() + + rules := getRules(ipt, kubeServicesChain) + if len(rules) <= 0 { + t.Errorf("skip loop back ip in kubeservice chain not exist") + return + } + if !rules[0].Jump.Matches("RETURN") || !rules[0].SourceAddress.Matches(test.src) { + t.Errorf("rules not match, expect jump: %s, got: %s; expect source address: %s, got: %s", "RETURN", rules[0].Jump.String(), test.src, rules[0].SourceAddress.String()) + } + }) + } +} diff --git a/pkg/proxy/ipvs/testing/util.go b/pkg/proxy/ipvs/testing/util.go index 2dbff14d171..c312923ac2b 100644 --- a/pkg/proxy/ipvs/testing/util.go +++ b/pkg/proxy/ipvs/testing/util.go @@ -43,8 +43,9 @@ type ExpectedIptablesChain map[string][]ExpectedIptablesRule // ExpectedIptablesRule is the expected iptables rules with jump chain and match ipset name type ExpectedIptablesRule struct { - JumpChain string - MatchSet string + SourceAddress string + JumpChain string + MatchSet string } // ExpectedIPSet is the expected ipset with set name and entries name