@@ -40,41 +40,53 @@ func (e *Error) Error() string {
40
40
}
41
41
42
42
type IPTables struct {
43
- path string
43
+ path string
44
+ hasCheck bool
45
+ hasWait bool
46
+
47
+ fmu * fileLock
44
48
}
45
49
46
50
func New () (* IPTables , error ) {
47
51
path , err := exec .LookPath ("iptables" )
48
52
if err != nil {
49
53
return nil , err
50
54
}
51
-
52
- return & IPTables {path }, nil
53
- }
54
-
55
- // Exists checks if given rulespec in specified table/chain exists
56
- func (ipt * IPTables ) Exists (table , chain string , rulespec ... string ) (bool , error ) {
57
- checkPresent , err := getIptablesHasCheckCommand ()
55
+ checkPresent , waitPresent , err := getIptablesCommandSupport ()
58
56
if err != nil {
59
- log .Printf ("Error checking iptables version, assuming version at least 1.4.11 : %v" , err )
57
+ log .Printf ("Error checking iptables version, assuming version at least 1.4.20 : %v" , err )
60
58
checkPresent = true
59
+ waitPresent = true
61
60
}
61
+ ipt := IPTables {
62
+ path : path ,
63
+ hasCheck : checkPresent ,
64
+ hasWait : waitPresent ,
65
+ }
66
+ if ! waitPresent {
67
+ ipt .fmu , err = newXtablesFileLock ()
68
+ if err != nil {
69
+ return nil , err
70
+ }
71
+ }
72
+ return & ipt , nil
73
+ }
62
74
63
- if ! checkPresent {
75
+ // Exists checks if given rulespec in specified table/chain exists
76
+ func (ipt * IPTables ) Exists (table , chain string , rulespec ... string ) (bool , error ) {
77
+ if ! ipt .hasCheck {
64
78
cmd := append ([]string {"-A" , chain }, rulespec ... )
65
79
return existsForOldIpTables (table , strings .Join (cmd , " " ))
66
- } else {
67
- cmd := append ([]string {"-t" , table , "-C" , chain }, rulespec ... )
68
- err := ipt .run (cmd ... )
69
-
70
- switch {
71
- case err == nil :
72
- return true , nil
73
- case err .(* Error ).ExitStatus () == 1 :
74
- return false , nil
75
- default :
76
- return false , err
77
- }
80
+ }
81
+ cmd := append ([]string {"-t" , table , "-C" , chain }, rulespec ... )
82
+ err := ipt .run (cmd ... )
83
+ switch {
84
+ case err == nil :
85
+ return true , nil
86
+ case err .(* Error ).ExitStatus () == 1 :
87
+ return false , nil
88
+ default :
89
+ return false , err
78
90
}
79
91
}
80
92
@@ -113,9 +125,21 @@ func (ipt *IPTables) Delete(table, chain string, rulespec ...string) error {
113
125
// List rules in specified table/chain
114
126
func (ipt * IPTables ) List (table , chain string ) ([]string , error ) {
115
127
var stdout , stderr bytes.Buffer
128
+ args := []string {ipt .path , "-t" , table , "-S" , chain }
129
+
130
+ if ipt .hasWait {
131
+ args = append (args , "--wait" )
132
+ } else {
133
+ ul , err := ipt .fmu .tryLock ()
134
+ if err != nil {
135
+ return nil , err
136
+ }
137
+ defer ul .Unlock ()
138
+ }
139
+
116
140
cmd := exec.Cmd {
117
141
Path : ipt .path ,
118
- Args : [] string { ipt . path , "--wait" , "-t" , table , "-S" , chain } ,
142
+ Args : args ,
119
143
Stdout : & stdout ,
120
144
Stderr : & stderr ,
121
145
}
@@ -136,8 +160,8 @@ func (ipt *IPTables) NewChain(table, chain string) error {
136
160
return ipt .run ("-t" , table , "-N" , chain )
137
161
}
138
162
139
- // ClearChain flushed (deletes all rules) in the specifed table/chain.
140
- // If the chain does not exist, new one will be created
163
+ // ClearChain flushed (deletes all rules) in the specified table/chain.
164
+ // If the chain does not exist, a new one will be created
141
165
func (ipt * IPTables ) ClearChain (table , chain string ) error {
142
166
err := ipt .NewChain (table , chain )
143
167
@@ -160,7 +184,16 @@ func (ipt *IPTables) DeleteChain(table, chain string) error {
160
184
161
185
func (ipt * IPTables ) run (args ... string ) error {
162
186
var stderr bytes.Buffer
163
- args = append ([]string {"--wait" }, args ... )
187
+ if ipt .hasWait {
188
+ args = append ([]string {"--wait" }, args ... )
189
+ } else {
190
+ ul , err := ipt .fmu .tryLock ()
191
+ if err != nil {
192
+ return err
193
+ }
194
+ defer ul .Unlock ()
195
+ }
196
+
164
197
cmd := exec.Cmd {
165
198
Path : ipt .path ,
166
199
Args : append ([]string {ipt .path }, args ... ),
@@ -174,19 +207,19 @@ func (ipt *IPTables) run(args ...string) error {
174
207
return nil
175
208
}
176
209
177
- // Checks if iptables has the "-C" flag
178
- func getIptablesHasCheckCommand () (bool , error ) {
210
+ // Checks if iptables has the "-C" and "--wait" flag
211
+ func getIptablesCommandSupport () (bool , bool , error ) {
179
212
vstring , err := getIptablesVersionString ()
180
213
if err != nil {
181
- return false , err
214
+ return false , false , err
182
215
}
183
216
184
217
v1 , v2 , v3 , err := extractIptablesVersion (vstring )
185
218
if err != nil {
186
- return false , err
219
+ return false , false , err
187
220
}
188
221
189
- return iptablesHasCheckCommand (v1 , v2 , v3 ), nil
222
+ return iptablesHasCheckCommand (v1 , v2 , v3 ), iptablesHasWaitCommand ( v1 , v2 , v3 ), nil
190
223
}
191
224
192
225
// getIptablesVersion returns the first three components of the iptables version.
@@ -242,6 +275,20 @@ func iptablesHasCheckCommand(v1 int, v2 int, v3 int) bool {
242
275
return false
243
276
}
244
277
278
+ // Checks if an iptables version is after 1.4.20, when --wait was added
279
+ func iptablesHasWaitCommand (v1 int , v2 int , v3 int ) bool {
280
+ if v1 > 1 {
281
+ return true
282
+ }
283
+ if v1 == 1 && v2 > 4 {
284
+ return true
285
+ }
286
+ if v1 == 1 && v2 == 4 && v3 >= 20 {
287
+ return true
288
+ }
289
+ return false
290
+ }
291
+
245
292
// Checks if a rule specification exists for a table
246
293
func existsForOldIpTables (table string , ruleSpec string ) (bool , error ) {
247
294
cmd := exec .Command ("iptables" , "-t" , table , "-S" )
0 commit comments