From f9b9b63ede4150b62089ba9f1bb88cc8a664d778 Mon Sep 17 00:00:00 2001 From: Jingyuan Liang Date: Wed, 16 Oct 2024 19:40:51 +0000 Subject: [PATCH] Implement --to-ports flag to specify explicit masquerading to-ports --- cmd/ip-masq-agent/ip-masq-agent.go | 47 ++++++++-- cmd/ip-masq-agent/ip-masq-agent_test.go | 115 +++++++++++++++++++++++- 2 files changed, 154 insertions(+), 8 deletions(-) diff --git a/cmd/ip-masq-agent/ip-masq-agent.go b/cmd/ip-masq-agent/ip-masq-agent.go index 5a30210..d56fa7a 100644 --- a/cmd/ip-masq-agent/ip-masq-agent.go +++ b/cmd/ip-masq-agent/ip-masq-agent.go @@ -23,6 +23,7 @@ import ( "fmt" "net" "os" + "strconv" "strings" "time" @@ -30,6 +31,7 @@ import ( "k8s.io/component-base/logs" "k8s.io/component-base/version/verflag" "k8s.io/ip-masq-agent/cmd/ip-masq-agent/testing/fakefs" + "k8s.io/ip-masq-agent/pkg/interval" "k8s.io/ip-masq-agent/pkg/version" "k8s.io/klog/v2" utiliptables "k8s.io/kubernetes/pkg/util/iptables" @@ -46,8 +48,14 @@ const ( var ( // name of nat chain for iptables masquerade rules - masqChain utiliptables.Chain - masqChainFlag = flag.String("masq-chain", "IP-MASQ-AGENT", `Name of nat chain for iptables masquerade rules.`) + masqChain utiliptables.Chain + masqChainFlag = flag.String("masq-chain", "IP-MASQ-AGENT", `Name of nat chain for iptables masquerade rules.`) + + // create MASQUERADE iptables rules with --to-ports flag + toPorts interval.Intervals + toPortsProtocols = []string{"tcp", "udp", "sctp"} + toPortsFlag = flag.String("to-ports", "", fmt.Sprintf(`Masquerade to specified ports only, example: "1024-29999,32768-65535"; applicable to %s protocols.`, strings.Join(toPortsProtocols, ", "))) + noMasqueradeAllReservedRangesFlag = flag.Bool("nomasq-all-reserved-ranges", false, "Whether to disable masquerade for all IPv4 ranges reserved by RFCs.") enableIPv6 = flag.Bool("enable-ipv6", false, "Whether to enable IPv6.") randomFully = flag.Bool("random-fully", true, "Whether to add --random-fully to the masquerade rule.") @@ -139,6 +147,14 @@ func main() { masqChain = utiliptables.Chain(*masqChainFlag) + if *toPortsFlag != "" { + tp, err := interval.ParseIntervals(*toPortsFlag) + if err != nil { + klog.Exitf("Invalid --to-ports flag %q: %v", *toPortsFlag, err) + } + toPorts = tp + } + c := NewMasqConfig(*noMasqueradeAllReservedRangesFlag) logs.InitLogs() @@ -299,7 +315,7 @@ func (m *MasqDaemon) syncMasqRules() error { } // masquerade all other traffic that is not bound for a --dst-type LOCAL destination - writeMasqRule(lines) + writeMasqRules(lines, toPorts) writeLine(lines, "COMMIT") @@ -338,7 +354,7 @@ func (m *MasqDaemon) syncMasqRulesIPv6() error { } // masquerade all other traffic that is not bound for a --dst-type LOCAL destination - writeMasqRule(lines6) + writeMasqRules(lines6, toPorts) writeLine(lines6, "COMMIT") @@ -385,14 +401,35 @@ func writeNonMasqRule(lines *bytes.Buffer, cidr string) { const masqRuleComment = `-m comment --comment "ip-masq-agent: outbound traffic is subject to MASQUERADE (must be last in chain)"` -func writeMasqRule(lines *bytes.Buffer) { +func writeMasqRules(lines *bytes.Buffer, toPorts interval.Intervals) { args := []string{masqRuleComment, "-j", "MASQUERADE"} if *randomFully { args = append(args, "--random-fully") } + + for _, protocol := range toPortsProtocols { + writeMasqToPortsRules(lines, append(args, "-p", protocol), toPorts) + } + writeRule(lines, utiliptables.Append, masqChain, args...) } +func writeMasqToPortsRules(lines *bytes.Buffer, args []string, toPorts interval.Intervals) { + size := toPorts.Size() + + for _, i := range toPorts { + args := args + + s := i.Size() + if size != s { + args = append(args, "-m", "statistic", "--mode", "random", "--probability", strconv.FormatFloat(float64(s)/float64(size), 'f', -1, 64)) + } + size -= s + + writeRule(lines, utiliptables.Append, masqChain, append(args, "--to-ports", i.String())...) + } +} + // Similar syntax to utiliptables.Interface.EnsureRule, except you don't pass a table // (you must write these rules under the line with the table name) func writeRule(lines *bytes.Buffer, position utiliptables.RulePosition, chain utiliptables.Chain, args ...string) { diff --git a/cmd/ip-masq-agent/ip-masq-agent_test.go b/cmd/ip-masq-agent/ip-masq-agent_test.go index 3ef8c5a..e04cdea 100644 --- a/cmd/ip-masq-agent/ip-masq-agent_test.go +++ b/cmd/ip-masq-agent/ip-masq-agent_test.go @@ -27,6 +27,7 @@ import ( "time" "k8s.io/ip-masq-agent/cmd/ip-masq-agent/testing/fakefs" + "k8s.io/ip-masq-agent/pkg/interval" utiliptables "k8s.io/kubernetes/pkg/util/iptables" iptest "k8s.io/kubernetes/pkg/util/iptables/testing" ) @@ -41,8 +42,8 @@ func TestMain(m *testing.M) { ec := 0 randomFully := " --random-fully" - for _, tc := range []struct{ - arg string + for _, tc := range []struct { + arg string want string }{ { @@ -52,7 +53,7 @@ func TestMain(m *testing.M) { arg: "false", }, { - arg: "true", + arg: "true", want: randomFully, }, } { @@ -476,6 +477,114 @@ func TestEnsurePostroutingJump(t *testing.T) { } } +// tests writeMasqRules +func TestWriteMasqRules(t *testing.T) { + var writeMasqRulesTests = []struct { + desc string + toPorts string + want string + }{ + { + desc: "default", + want: string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + "\n", + }, + { + desc: "single range", + toPorts: "1024-29999", + want: string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + "\n", + }, + { + desc: "double ranges", + toPorts: "1024-29999,32768-65535", + want: string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp -m statistic --mode random --probability 0.469292562840114 --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp --to-ports 32768-65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp -m statistic --mode random --probability 0.469292562840114 --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp --to-ports 32768-65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp -m statistic --mode random --probability 0.469292562840114 --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp --to-ports 32768-65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + "\n", + }, + { + desc: "triple ranges", + toPorts: "1024-29999,32768-49151,61000-65535", + want: string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp -m statistic --mode random --probability 0.5807279140612474 --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp -m statistic --mode random --probability 0.7831739961759082 --to-ports 32768-49151\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp --to-ports 61000-65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp -m statistic --mode random --probability 0.5807279140612474 --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp -m statistic --mode random --probability 0.7831739961759082 --to-ports 32768-49151\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp --to-ports 61000-65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp -m statistic --mode random --probability 0.5807279140612474 --to-ports 1024-29999\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp -m statistic --mode random --probability 0.7831739961759082 --to-ports 32768-49151\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp --to-ports 61000-65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + "\n", + }, + { + desc: "individual ports", + toPorts: "1024,65535", + want: string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp -m statistic --mode random --probability 0.5 --to-ports 1024\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p tcp --to-ports 65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp -m statistic --mode random --probability 0.5 --to-ports 1024\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p udp --to-ports 65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp -m statistic --mode random --probability 0.5 --to-ports 1024\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + " -p sctp --to-ports 65535\n" + + string(utiliptables.Append) + " " + string(masqChain) + " " + masqRuleComment + + ` -j MASQUERADE` + wantRandomFully + "\n", + }, + } + + for _, tt := range writeMasqRulesTests { + t.Run(tt.desc, func(t *testing.T) { + var toPorts interval.Intervals + if tt.toPorts != "" { + tp, err := interval.ParseIntervals(tt.toPorts) + if err != nil { + t.Fatalf("Invalid --to-ports spec: %q", tt.toPorts) + } + toPorts = tp + } + + lines := bytes.NewBuffer(nil) + writeMasqRules(lines, toPorts) + + s := lines.String() + if s != tt.want { + t.Errorf("writeMasqRules(lines, %q):\n got: %q\n want: %q", tt.toPorts, s, tt.want) + } + }) + } +} + // tests writeNonMasqRule func TestWriteNonMasqRule(t *testing.T) { var writeNonMasqRuleTests = []struct {