@@ -14,7 +14,7 @@ import (
1414 "github.com/pkg/errors"
1515)
1616
17- const SWIFT = "SWIFT-POSTROUTING"
17+ const SWIFTPOSTROUTING = "SWIFT-POSTROUTING"
1818
1919type IPtablesProvider struct {}
2020
@@ -37,32 +37,62 @@ func (service *HTTPRestService) programSNATRules(req *cns.CreateNetworkContainer
3737 return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to create iptables interface : %v" , err )
3838 }
3939
40- chainExist , err := ipt .ChainExists (iptables .Nat , SWIFT )
40+ chainExist , err := ipt .ChainExists (iptables .Nat , SWIFTPOSTROUTING )
4141 if err != nil {
42- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of SWIFT chain: %v" , err )
42+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of SWIFT-POSTROUTING chain: %v" , err )
4343 }
4444 if ! chainExist { // create and append chain if it doesn't exist
45- logger .Printf ("[Azure CNS] Creating SWIFT Chain ..." )
46- err = ipt .NewChain (iptables .Nat , SWIFT )
45+ logger .Printf ("[Azure CNS] Creating SWIFT-POSTROUTING Chain ..." )
46+ err = ipt .NewChain (iptables .Nat , SWIFTPOSTROUTING )
4747 if err != nil {
48- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to create SWIFT chain : " + err .Error ()
49- }
50- logger .Printf ("[Azure CNS] Append SWIFT Chain to POSTROUTING ..." )
51- err = ipt .Append (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
52- if err != nil {
53- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to append SWIFT chain : " + err .Error ()
48+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to create SWIFT-POSTROUTING chain : " + err .Error ()
5449 }
5550 }
5651
57- postroutingToSwiftJumpexist , err := ipt .Exists (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
52+ // reconcile jump to SWIFT-POSTROUTING chain
53+ rules , err := ipt .List (iptables .Nat , iptables .Postrouting )
5854 if err != nil {
59- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of POSTROUTING to SWIFT chain jump: %v" , err )
55+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check rules in postrouting chain of nat table: %v" , err )
56+ }
57+ swiftRuleIndex := len (rules ) // append if neither jump rule from POSTROUTING is found
58+ // one time migration from old SWIFT chain
59+ // previously, CNI may have a jump to the SWIFT chain-- our jump to SWIFT-POSTROUTING needs to happen first
60+ for index , rule := range rules {
61+ if rule == "-A POSTROUTING -j SWIFT" {
62+ // jump to SWIFT comes before jump to SWIFT-POSTROUTING, so potential reordering required
63+ swiftRuleIndex = index
64+ break
65+ }
66+ if rule == "-A POSTROUTING -j SWIFT-POSTROUTING" {
67+ // jump to SWIFT-POSTROUTING comes before jump to SWIFT, which requires no further action
68+ swiftRuleIndex = - 1
69+ break
70+ }
6071 }
61- if ! postroutingToSwiftJumpexist {
62- logger .Printf ("[Azure CNS] Append SWIFT Chain to POSTROUTING ..." )
63- err = ipt .Append (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
72+ if swiftRuleIndex != - 1 {
73+ // jump SWIFT rule exists, insert SWIFT-POSTROUTING rule at the same position so it ends up running first
74+ // first, remove any existing SWIFT-POSTROUTING rules to avoid duplicates
75+ // note: inserting at len(rules) and deleting a jump to SWIFT-POSTROUTING is mutually exclusive
76+ swiftPostroutingExists , err := ipt .Exists (iptables .Nat , iptables .Postrouting , "-j" , SWIFTPOSTROUTING )
77+ if err != nil {
78+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of SWIFT-POSTROUTING rule: %v" , err )
79+ }
80+ if swiftPostroutingExists {
81+ err = ipt .Delete (iptables .Nat , iptables .Postrouting , "-j" , SWIFTPOSTROUTING )
82+ if err != nil {
83+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to delete existing SWIFT-POSTROUTING rule : " + err .Error ()
84+ }
85+ }
86+
87+ // slice index is 0-based, iptables insert is 1-based, but list also gives us the -P POSTROUTING ACCEPT
88+ // as the first rule so swiftRuleIndex gives us the correct 1-indexed iptables position.
89+ // Example:
90+ // -P POSTROUTING ACCEPT is at swiftRuleIndex 0
91+ // -A POSTROUTING -j SWIFT is at swiftRuleIndex 1, and iptables index 1
92+ logger .Printf ("[Azure CNS] Inserting SWIFT-POSTROUTING Chain at iptables position %d" , swiftRuleIndex )
93+ err = ipt .Insert (iptables .Nat , iptables .Postrouting , swiftRuleIndex , "-j" , SWIFTPOSTROUTING )
6494 if err != nil {
65- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to append SWIFT chain : " + err .Error ()
95+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert SWIFT-POSTROUTING chain : " + err .Error ()
6696 }
6797 }
6898
@@ -71,39 +101,47 @@ func (service *HTTPRestService) programSNATRules(req *cns.CreateNetworkContainer
71101 // put the ip address in standard cidr form (where we zero out the parts that are not relevant)
72102 _ , podSubnet , _ := net .ParseCIDR (v .IPAddress + "/" + fmt .Sprintf ("%d" , req .IPConfiguration .IPSubnet .PrefixLength ))
73103
74- snatUDPRuleExists , err := ipt .Exists (iptables .Nat , SWIFT , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .UDP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
75- if err != nil {
76- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of pod SNAT UDP rule : %v" , err )
104+ // define all rules we want in the chain
105+ rules := [][]string {
106+ {"-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .UDP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ()},
107+ {"-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ()},
108+ {"-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureIMDS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .HTTPPort ), "-j" , iptables .Snat , "--to" , req .HostPrimaryIP },
77109 }
78- if ! snatUDPRuleExists {
79- logger .Printf ("[Azure CNS] Inserting pod SNAT UDP rule ..." )
80- err = ipt .Insert (iptables .Nat , SWIFT , 1 , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .UDP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
110+
111+ // check if all rules exist
112+ allRulesExist := true
113+ for _ , rule := range rules {
114+ exists , err := ipt .Exists (iptables .Nat , SWIFTPOSTROUTING , rule ... )
81115 if err != nil {
82- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert pod SNAT UDP rule : " + err .Error ()
116+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of rule: %v" , err )
117+ }
118+ if ! exists {
119+ allRulesExist = false
120+ break
83121 }
84122 }
85123
86- snatPodTCPRuleExists , err := ipt .Exists (iptables .Nat , SWIFT , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
124+ // get current rule count in SWIFT-POSTROUTING chain
125+ currentRules , err := ipt .List (iptables .Nat , SWIFTPOSTROUTING )
87126 if err != nil {
88- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of pod SNAT TCP rule : %v" , err )
127+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to list rules in SWIFT-POSTROUTING chain : %v" , err )
89128 }
90- if ! snatPodTCPRuleExists {
91- logger .Printf ("[Azure CNS] Inserting pod SNAT TCP rule ..." )
92- err = ipt .Insert (iptables .Nat , SWIFT , 1 , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
129+
130+ // if rule count doesn't match or not all rules exist, reconcile
131+ // add one because there is always a singular starting rule in the chain, in addition to the ones we add
132+ if len (currentRules ) != len (rules )+ 1 || ! allRulesExist {
133+ logger .Printf ("[Azure CNS] Reconciling SWIFT-POSTROUTING chain rules" )
134+
135+ err = ipt .ClearChain (iptables .Nat , SWIFTPOSTROUTING )
93136 if err != nil {
94- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert pod SNAT TCP rule : " + err .Error ()
137+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to flush SWIFT-POSTROUTING chain : " + err .Error ()
95138 }
96- }
97139
98- snatIMDSRuleexist , err := ipt .Exists (iptables .Nat , SWIFT , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureIMDS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .HTTPPort ), "-j" , iptables .Snat , "--to" , req .HostPrimaryIP )
99- if err != nil {
100- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of pod SNAT IMDS rule : %v" , err )
101- }
102- if ! snatIMDSRuleexist {
103- logger .Printf ("[Azure CNS] Inserting pod SNAT IMDS rule ..." )
104- err = ipt .Insert (iptables .Nat , SWIFT , 1 , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureIMDS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .HTTPPort ), "-j" , iptables .Snat , "--to" , req .HostPrimaryIP )
105- if err != nil {
106- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert pod SNAT IMDS rule : " + err .Error ()
140+ for _ , rule := range rules {
141+ err = ipt .Append (iptables .Nat , SWIFTPOSTROUTING , rule ... )
142+ if err != nil {
143+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to append rule to SWIFT-POSTROUTING chain : " + err .Error ()
144+ }
107145 }
108146 }
109147
0 commit comments