Skip to content

Commit 45b54e0

Browse files
author
Joseph Chen
committed
Refactor IPTable Rules
1 parent 9427f7f commit 45b54e0

File tree

3 files changed

+206
-154
lines changed

3 files changed

+206
-154
lines changed

pkg/networkutils/network.go

+94-50
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ func (n *linuxNetwork) updateHostIptablesRules(vpcCIDRs []string, primaryMAC str
407407
if err := n.updateIptablesRules(iptablesConnmarkRules, ipt); err != nil {
408408
return err
409409
}
410+
err = n.cleanOldNatChains(ipt)
411+
if err != nil {
412+
return err
413+
}
410414
}
411415
return nil
412416
}
@@ -429,15 +433,13 @@ func (n *linuxNetwork) buildIptablesSNATRules(vpcCIDRs []string, primaryAddr *ne
429433
log.Debugf("Total CIDRs to program - %d", len(allCIDRs))
430434
// build IPTABLES chain for SNAT of non-VPC outbound traffic and excluded CIDRs
431435
var chains []string
432-
for i := 0; i <= len(allCIDRs); i++ {
433-
chain := fmt.Sprintf("AWS-SNAT-CHAIN-%d", i)
434-
log.Debugf("Setup Host Network: iptables -N %s -t nat", chain)
435-
if err := ipt.NewChain("nat", chain); err != nil && !containChainExistErr(err) {
436-
log.Errorf("ipt.NewChain error for chain [%s]: %v", chain, err)
437-
return []iptablesRule{}, errors.Wrapf(err, "host network setup: failed to add chain")
438-
}
439-
chains = append(chains, chain)
436+
chain := "AWS-SNAT-CHAIN-0"
437+
log.Debugf("Setup Host Network: iptables -N %s -t nat", chain)
438+
if err := ipt.NewChain("nat", chain); err != nil && !containChainExistErr(err) {
439+
log.Errorf("ipt.NewChain error for chain [%s]: %v", chain, err)
440+
return []iptablesRule{}, errors.Wrapf(err, "host network setup: failed to add chain")
440441
}
442+
chains = append(chains, chain)
441443

442444
// build SNAT rules for outbound non-VPC traffic
443445
var iptableRules []iptablesRule
@@ -451,23 +453,22 @@ func (n *linuxNetwork) buildIptablesSNATRules(vpcCIDRs []string, primaryAddr *ne
451453
"-m", "comment", "--comment", "AWS SNAT CHAIN", "-j", "AWS-SNAT-CHAIN-0",
452454
}})
453455

454-
for i, cidr := range allCIDRs {
455-
curChain := chains[i]
456-
curName := fmt.Sprintf("[%d] AWS-SNAT-CHAIN", i)
457-
nextChain := chains[i+1]
456+
for _, cidr := range allCIDRs {
457+
curChain := "AWS-SNAT-CHAIN-0"
458+
curName := "AWS-SNAT-CHAIN-0"
458459
comment := "AWS SNAT CHAIN"
459460
if cidr.isExclusion {
460461
comment += " EXCLUSION"
461462
}
462-
log.Debugf("Setup Host Network: iptables -A %s ! -d %s -t nat -j %s", curChain, cidr, nextChain)
463+
log.Debugf("Setup Host Network: iptables -A %s -d %s -t nat -j %s", "AWS-SNAT-CHAIN-0", cidr, "RETURN")
463464

464465
iptableRules = append(iptableRules, iptablesRule{
465466
name: curName,
466467
shouldExist: !n.useExternalSNAT,
467468
table: "nat",
468469
chain: curChain,
469470
rule: []string{
470-
"!", "-d", cidr.cidr, "-m", "comment", "--comment", comment, "-j", nextChain,
471+
"-d", cidr.cidr, "-m", "comment", "--comment", comment, "-j", "RETURN",
471472
}})
472473
}
473474

@@ -489,22 +490,31 @@ func (n *linuxNetwork) buildIptablesSNATRules(vpcCIDRs []string, primaryAddr *ne
489490
}
490491
}
491492

492-
lastChain := chains[len(chains)-1]
493-
iptableRules = append(iptableRules, iptablesRule{
494-
name: "last SNAT rule for non-VPC outbound traffic",
495-
shouldExist: !n.useExternalSNAT,
496-
table: "nat",
497-
chain: lastChain,
498-
rule: snatRule,
499-
})
500-
501493
snatStaleRules, err := computeStaleIptablesRules(ipt, "nat", "AWS-SNAT-CHAIN", iptableRules, chains)
502494
if err != nil {
503495
return []iptablesRule{}, err
504496
}
505497

506498
iptableRules = append(iptableRules, snatStaleRules...)
507499

500+
// Force delete the SNAT rule as we want this to be the last rule of the AWS-SNAT-CHAIN-0 chain
501+
iptableRules = append(iptableRules, iptablesRule{
502+
name: "last SNAT rule for non-VPC outbound traffic",
503+
shouldExist: false,
504+
table: "nat",
505+
chain: "AWS-SNAT-CHAIN-0",
506+
rule: snatRule,
507+
})
508+
509+
// Force add the SNAT rule back so it is the last rule of the AWS-SNAT-CHAIN-0 chain
510+
iptableRules = append(iptableRules, iptablesRule{
511+
name: "last SNAT rule for non-VPC outbound traffic",
512+
shouldExist: !n.useExternalSNAT,
513+
table: "nat",
514+
chain: "AWS-SNAT-CHAIN-0",
515+
rule: snatRule,
516+
})
517+
508518
iptableRules = append(iptableRules, iptablesRule{
509519
name: "connmark for primary ENI",
510520
shouldExist: n.nodePortSupportEnabled,
@@ -551,16 +561,15 @@ func (n *linuxNetwork) buildIptablesConnmarkRules(vpcCIDRs []string, ipt iptable
551561
excludeCIDRs := sets.NewString(n.excludeSNATCIDRs...)
552562

553563
log.Debugf("Total CIDRs to exempt from connmark rules - %d", len(allCIDRs))
564+
554565
var chains []string
555-
for i := 0; i <= len(allCIDRs); i++ {
556-
chain := fmt.Sprintf("AWS-CONNMARK-CHAIN-%d", i)
557-
log.Debugf("Setup Host Network: iptables -N %s -t nat", chain)
558-
if err := ipt.NewChain("nat", chain); err != nil && !containChainExistErr(err) {
559-
log.Errorf("ipt.NewChain error for chain [%s]: %v", chain, err)
560-
return []iptablesRule{}, errors.Wrapf(err, "host network setup: failed to add chain")
561-
}
562-
chains = append(chains, chain)
566+
chain := "AWS-CONNMARK-CHAIN-0"
567+
log.Debugf("Setup Host Network: iptables -N %s -t nat", chain)
568+
if err := ipt.NewChain("nat", chain); err != nil && !containChainExistErr(err) {
569+
log.Errorf("ipt.NewChain error for chain [%s]: %v", chain, err)
570+
return []iptablesRule{}, errors.Wrapf(err, "host network setup: failed to add chain")
563571
}
572+
chains = append(chains, chain)
564573

565574
var iptableRules []iptablesRule
566575
log.Debugf("Setup Host Network: iptables -t nat -A PREROUTING -i %s+ -m comment --comment \"AWS, outbound connections\" -j AWS-CONNMARK-CHAIN-0", n.vethPrefix)
@@ -585,37 +594,25 @@ func (n *linuxNetwork) buildIptablesConnmarkRules(vpcCIDRs []string, ipt iptable
585594
"-j", "AWS-CONNMARK-CHAIN-0",
586595
}})
587596

588-
for i, cidr := range allCIDRs {
589-
curChain := chains[i]
590-
curName := fmt.Sprintf("[%d] AWS-SNAT-CHAIN", i)
591-
nextChain := chains[i+1]
597+
for _, cidr := range allCIDRs {
598+
curChain := "AWS-CONNMARK-CHAIN-0"
599+
curName := "AWS-CONNMARK-CHAIN-0"
592600
comment := "AWS CONNMARK CHAIN, VPC CIDR"
593601
if excludeCIDRs.Has(cidr) {
594602
comment = "AWS CONNMARK CHAIN, EXCLUDED CIDR"
595603
}
596-
log.Debugf("Setup Host Network: iptables -A %s ! -d %s -t nat -j %s", curChain, cidr, nextChain)
604+
log.Debugf("Setup Host Network: iptables -A %s -d %s -t nat -j %s", "AWS-CONNMARK-CHAIN-0", cidr, "RETURN")
597605

598606
iptableRules = append(iptableRules, iptablesRule{
599607
name: curName,
600608
shouldExist: !n.useExternalSNAT,
601609
table: "nat",
602610
chain: curChain,
603611
rule: []string{
604-
"!", "-d", cidr, "-m", "comment", "--comment", comment, "-j", nextChain,
612+
"-d", cidr, "-m", "comment", "--comment", comment, "-j", "RETURN",
605613
}})
606614
}
607615

608-
iptableRules = append(iptableRules, iptablesRule{
609-
name: "connmark rule for external outbound traffic",
610-
shouldExist: !n.useExternalSNAT,
611-
table: "nat",
612-
chain: chains[len(chains)-1],
613-
rule: []string{
614-
"-m", "comment", "--comment", "AWS, CONNMARK", "-j", "CONNMARK",
615-
"--set-xmark", fmt.Sprintf("%#x/%#x", n.mainENIMark, n.mainENIMark),
616-
},
617-
})
618-
619616
// Force delete existing restore mark rule so that the subsequent rule gets added to the end
620617
iptableRules = append(iptableRules, iptablesRule{
621618
name: "connmark to fwmark copy",
@@ -647,14 +644,37 @@ func (n *linuxNetwork) buildIptablesConnmarkRules(vpcCIDRs []string, ipt iptable
647644
}
648645
iptableRules = append(iptableRules, connmarkStaleRules...)
649646

647+
// Force delete the CONNMARK rule as we want this to be the last rule of the AWS-CONNMARK-CHAIN-0 chain
648+
iptableRules = append(iptableRules, iptablesRule{
649+
name: "connmark rule for external outbound traffic",
650+
shouldExist: false,
651+
table: "nat",
652+
chain: "AWS-CONNMARK-CHAIN-0",
653+
rule: []string{
654+
"-m", "comment", "--comment", "AWS, CONNMARK", "-j", "CONNMARK",
655+
"--set-xmark", fmt.Sprintf("%#x/%#x", n.mainENIMark, n.mainENIMark),
656+
},
657+
})
658+
659+
// Force add the CONNMARK rule as we want this to be the last rule of the AWS-CONNMARK-CHAIN-0 chain
660+
iptableRules = append(iptableRules, iptablesRule{
661+
name: "connmark rule for external outbound traffic",
662+
shouldExist: !n.useExternalSNAT,
663+
table: "nat",
664+
chain: "AWS-CONNMARK-CHAIN-0",
665+
rule: []string{
666+
"-m", "comment", "--comment", "AWS, CONNMARK", "-j", "CONNMARK",
667+
"--set-xmark", fmt.Sprintf("%#x/%#x", n.mainENIMark, n.mainENIMark),
668+
},
669+
})
670+
650671
log.Debugf("iptableRules: %v", iptableRules)
651672
return iptableRules, nil
652673
}
653674

654675
func (n *linuxNetwork) updateIptablesRules(iptableRules []iptablesRule, ipt iptableswrapper.IPTablesIface) error {
655676
for _, rule := range iptableRules {
656677
log.Debugf("execute iptable rule : %s", rule.name)
657-
658678
exists, err := ipt.Exists(rule.table, rule.chain, rule.rule...)
659679
log.Debugf("rule %v exists %v, err %v", rule, exists, err)
660680
if err != nil {
@@ -714,14 +734,38 @@ func listCurrentIptablesRules(ipt iptableswrapper.IPTablesIface, table, chainPre
714734
return toClear, nil
715735
}
716736

737+
func (n *linuxNetwork) cleanOldNatChains(ipt iptableswrapper.IPTablesIface) error {
738+
existingChains, err := ipt.ListChains("nat")
739+
if err != nil {
740+
return errors.Wrapf(err, "host network setup: failed to list iptables %s chains", "nat")
741+
}
742+
for _, chain := range existingChains {
743+
if !strings.HasPrefix(chain, "AWS-CONNMARK-CHAIN") && !strings.HasPrefix(chain, "AWS-SNAT-CHAIN") {
744+
continue
745+
}
746+
parsedChain := strings.Split(chain, "-")
747+
num, err := strconv.Atoi(parsedChain[len(parsedChain)-1])
748+
if err == nil {
749+
if num == 0 {
750+
continue
751+
}
752+
err = ipt.DeleteChain("nat", chain)
753+
if err != nil {
754+
return errors.Wrapf(err, "Failed to delete chain %s", chain)
755+
}
756+
}
757+
}
758+
return nil
759+
}
760+
717761
func computeStaleIptablesRules(ipt iptableswrapper.IPTablesIface, table, chainPrefix string, newRules []iptablesRule, chains []string) ([]iptablesRule, error) {
718762
var staleRules []iptablesRule
719763
existingRules, err := listCurrentIptablesRules(ipt, table, chainPrefix)
720764
if err != nil {
721765
return []iptablesRule{}, errors.Wrapf(err, "host network setup: failed to list rules from table %s with chain prefix %s", table, chainPrefix)
722766
}
723767
activeChains := sets.NewString(chains...)
724-
log.Debugf("Setup Host Network: computing stale iptables rules for %s table with chain prefix %s")
768+
log.Debugf("Setup Host Network: computing stale iptables rules for %s table with chain prefix %s", table, chainPrefix)
725769
for _, staleRule := range existingRules {
726770
if len(staleRule.rule) == 0 && activeChains.Has(staleRule.chain) {
727771
log.Debugf("Setup Host Network: active chain found: %s", staleRule.chain)

0 commit comments

Comments
 (0)