iptables_test.go 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316
  1. // +build linux
  2. /*
  3. Copyright 2014 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package iptables
  15. import (
  16. "bytes"
  17. "fmt"
  18. "net"
  19. "os"
  20. "reflect"
  21. "strings"
  22. "testing"
  23. "time"
  24. "k8s.io/apimachinery/pkg/util/sets"
  25. "k8s.io/kubernetes/pkg/util/dbus"
  26. "k8s.io/utils/exec"
  27. fakeexec "k8s.io/utils/exec/testing"
  28. )
  29. const TestLockfilePath = "xtables.lock"
  30. func protocolStr(protocol Protocol) string {
  31. if protocol == ProtocolIpv4 {
  32. return "IPv4"
  33. }
  34. return "IPv6"
  35. }
  36. func testIPTablesVersionCmds(t *testing.T, protocol Protocol) {
  37. version := " v1.9.22"
  38. iptablesCmd := iptablesCommand(protocol)
  39. iptablesRestoreCmd := iptablesRestoreCommand(protocol)
  40. protoStr := protocolStr(protocol)
  41. fcmd := fakeexec.FakeCmd{
  42. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  43. // iptables version response (for runner instantiation)
  44. func() ([]byte, error) { return []byte(iptablesCmd + version), nil },
  45. // iptables-restore version response (for runner instantiation)
  46. func() ([]byte, error) { return []byte(iptablesRestoreCmd + version), nil },
  47. // iptables version response (for call to runner.GetVersion())
  48. func() ([]byte, error) { return []byte(iptablesCmd + version), nil },
  49. },
  50. }
  51. fexec := fakeexec.FakeExec{
  52. CommandScript: []fakeexec.FakeCommandAction{
  53. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  54. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  55. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  56. },
  57. }
  58. runner := New(&fexec, dbus.NewFake(nil, nil), protocol)
  59. defer runner.Destroy()
  60. // Check that proper iptables version command was used during runner instantiation
  61. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll(iptablesCmd, "--version") {
  62. t.Errorf("%s runner instantiate: Expected cmd '%s --version', Got '%s'", protoStr, iptablesCmd, fcmd.CombinedOutputLog[0])
  63. }
  64. // Check that proper iptables restore version command was used during runner instantiation
  65. if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll(iptablesRestoreCmd, "--version") {
  66. t.Errorf("%s runner instantiate: Expected cmd '%s --version', Got '%s'", protoStr, iptablesRestoreCmd, fcmd.CombinedOutputLog[1])
  67. }
  68. _, err := runner.GetVersion()
  69. if err != nil {
  70. t.Errorf("%s GetVersion: Expected success, got %v", protoStr, err)
  71. }
  72. // Check that proper iptables version command was used for runner.GetVersion
  73. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll(iptablesCmd, "--version") {
  74. t.Errorf("%s GetVersion: Expected cmd '%s --version', Got '%s'", protoStr, iptablesCmd, fcmd.CombinedOutputLog[2])
  75. }
  76. }
  77. func TestIPTablesVersionCmdsIPv4(t *testing.T) {
  78. testIPTablesVersionCmds(t, ProtocolIpv4)
  79. }
  80. func TestIPTablesVersionCmdsIPv6(t *testing.T) {
  81. testIPTablesVersionCmds(t, ProtocolIpv6)
  82. }
  83. func testEnsureChain(t *testing.T, protocol Protocol) {
  84. protoStr := protocolStr(protocol)
  85. fcmd := fakeexec.FakeCmd{
  86. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  87. // iptables version check
  88. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  89. // iptables-restore version check
  90. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  91. // Success.
  92. func() ([]byte, error) { return []byte{}, nil },
  93. // Exists.
  94. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  95. // Failure.
  96. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 2} },
  97. },
  98. }
  99. fexec := fakeexec.FakeExec{
  100. CommandScript: []fakeexec.FakeCommandAction{
  101. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  102. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  103. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  104. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  105. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  106. },
  107. }
  108. runner := New(&fexec, dbus.NewFake(nil, nil), protocol)
  109. defer runner.Destroy()
  110. // Success.
  111. exists, err := runner.EnsureChain(TableNAT, Chain("FOOBAR"))
  112. if err != nil {
  113. t.Errorf("%s new chain: Expected success, got %v", protoStr, err)
  114. }
  115. if exists {
  116. t.Errorf("%s new chain: Expected exists = false", protoStr)
  117. }
  118. if fcmd.CombinedOutputCalls != 3 {
  119. t.Errorf("%s new chain: Expected 3 CombinedOutput() calls, got %d", protoStr, fcmd.CombinedOutputCalls)
  120. }
  121. cmd := iptablesCommand(protocol)
  122. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll(cmd, "-t", "nat", "-N", "FOOBAR") {
  123. t.Errorf("%s new chain: Expected cmd containing '%s -t nat -N FOOBAR', got %s", protoStr, cmd, fcmd.CombinedOutputLog[2])
  124. }
  125. // Exists.
  126. exists, err = runner.EnsureChain(TableNAT, Chain("FOOBAR"))
  127. if err != nil {
  128. t.Errorf("%s existing chain: Expected success, got %v", protoStr, err)
  129. }
  130. if !exists {
  131. t.Errorf("%s existing chain: Expected exists = true", protoStr)
  132. }
  133. // Simulate failure.
  134. _, err = runner.EnsureChain(TableNAT, Chain("FOOBAR"))
  135. if err == nil {
  136. t.Errorf("%s: Expected failure", protoStr)
  137. }
  138. }
  139. func TestEnsureChainIpv4(t *testing.T) {
  140. testEnsureChain(t, ProtocolIpv4)
  141. }
  142. func TestEnsureChainIpv6(t *testing.T) {
  143. testEnsureChain(t, ProtocolIpv6)
  144. }
  145. func TestFlushChain(t *testing.T) {
  146. fcmd := fakeexec.FakeCmd{
  147. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  148. // iptables version check
  149. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  150. // iptables-restore version check
  151. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  152. // Success.
  153. func() ([]byte, error) { return []byte{}, nil },
  154. // Failure.
  155. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  156. },
  157. }
  158. fexec := fakeexec.FakeExec{
  159. CommandScript: []fakeexec.FakeCommandAction{
  160. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  161. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  162. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  163. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  164. },
  165. }
  166. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  167. defer runner.Destroy()
  168. // Success.
  169. err := runner.FlushChain(TableNAT, Chain("FOOBAR"))
  170. if err != nil {
  171. t.Errorf("expected success, got %v", err)
  172. }
  173. if fcmd.CombinedOutputCalls != 3 {
  174. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  175. }
  176. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-F", "FOOBAR") {
  177. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  178. }
  179. // Failure.
  180. err = runner.FlushChain(TableNAT, Chain("FOOBAR"))
  181. if err == nil {
  182. t.Errorf("expected failure")
  183. }
  184. }
  185. func TestDeleteChain(t *testing.T) {
  186. fcmd := fakeexec.FakeCmd{
  187. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  188. // iptables version check
  189. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  190. // iptables-restore version check
  191. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  192. // Success.
  193. func() ([]byte, error) { return []byte{}, nil },
  194. // Failure.
  195. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  196. },
  197. }
  198. fexec := fakeexec.FakeExec{
  199. CommandScript: []fakeexec.FakeCommandAction{
  200. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  201. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  202. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  203. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  204. },
  205. }
  206. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  207. defer runner.Destroy()
  208. // Success.
  209. err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
  210. if err != nil {
  211. t.Errorf("expected success, got %v", err)
  212. }
  213. if fcmd.CombinedOutputCalls != 3 {
  214. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  215. }
  216. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-X", "FOOBAR") {
  217. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  218. }
  219. // Failure.
  220. err = runner.DeleteChain(TableNAT, Chain("FOOBAR"))
  221. if err == nil {
  222. t.Errorf("expected failure")
  223. }
  224. }
  225. func TestEnsureRuleAlreadyExists(t *testing.T) {
  226. fcmd := fakeexec.FakeCmd{
  227. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  228. // iptables version check
  229. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  230. // iptables-restore version check
  231. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  232. // Success.
  233. func() ([]byte, error) { return []byte{}, nil },
  234. },
  235. }
  236. fexec := fakeexec.FakeExec{
  237. CommandScript: []fakeexec.FakeCommandAction{
  238. // iptables version check
  239. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  240. // iptables-restore version check
  241. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  242. // The second Command() call is checking the rule. Success of that exec means "done".
  243. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  244. },
  245. }
  246. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  247. defer runner.Destroy()
  248. exists, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
  249. if err != nil {
  250. t.Errorf("expected success, got %v", err)
  251. }
  252. if !exists {
  253. t.Errorf("expected exists = true")
  254. }
  255. if fcmd.CombinedOutputCalls != 3 {
  256. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  257. }
  258. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
  259. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  260. }
  261. }
  262. func TestEnsureRuleNew(t *testing.T) {
  263. fcmd := fakeexec.FakeCmd{
  264. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  265. // iptables version check
  266. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  267. // iptables-restore version check
  268. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  269. // Status 1 on the first call.
  270. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  271. // Success on the second call.
  272. func() ([]byte, error) { return []byte{}, nil },
  273. },
  274. }
  275. fexec := fakeexec.FakeExec{
  276. CommandScript: []fakeexec.FakeCommandAction{
  277. // iptables version check
  278. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  279. // iptables-restore version check
  280. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  281. // The second Command() call is checking the rule. Failure of that means create it.
  282. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  283. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  284. },
  285. }
  286. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  287. defer runner.Destroy()
  288. exists, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
  289. if err != nil {
  290. t.Errorf("expected success, got %v", err)
  291. }
  292. if exists {
  293. t.Errorf("expected exists = false")
  294. }
  295. if fcmd.CombinedOutputCalls != 4 {
  296. t.Errorf("expected 4 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  297. }
  298. if !sets.NewString(fcmd.CombinedOutputLog[3]...).HasAll("iptables", "-t", "nat", "-A", "OUTPUT", "abc", "123") {
  299. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[3])
  300. }
  301. }
  302. func TestEnsureRuleErrorChecking(t *testing.T) {
  303. fcmd := fakeexec.FakeCmd{
  304. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  305. // iptables version check
  306. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  307. // iptables-restore version check
  308. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  309. // Status 2 on the first call.
  310. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 2} },
  311. },
  312. }
  313. fexec := fakeexec.FakeExec{
  314. CommandScript: []fakeexec.FakeCommandAction{
  315. // iptables version check
  316. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  317. // iptables-restore version check
  318. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  319. // The second Command() call is checking the rule. Failure of that means create it.
  320. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  321. },
  322. }
  323. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  324. defer runner.Destroy()
  325. _, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
  326. if err == nil {
  327. t.Errorf("expected failure")
  328. }
  329. if fcmd.CombinedOutputCalls != 3 {
  330. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  331. }
  332. }
  333. func TestEnsureRuleErrorCreating(t *testing.T) {
  334. fcmd := fakeexec.FakeCmd{
  335. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  336. // iptables version check
  337. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  338. // iptables-restore version check
  339. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  340. // Status 1 on the first call.
  341. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  342. // Status 1 on the second call.
  343. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  344. },
  345. }
  346. fexec := fakeexec.FakeExec{
  347. CommandScript: []fakeexec.FakeCommandAction{
  348. // iptables version check
  349. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  350. // iptables-restore version check
  351. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  352. // The second Command() call is checking the rule. Failure of that means create it.
  353. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  354. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  355. },
  356. }
  357. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  358. defer runner.Destroy()
  359. _, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
  360. if err == nil {
  361. t.Errorf("expected failure")
  362. }
  363. if fcmd.CombinedOutputCalls != 4 {
  364. t.Errorf("expected 4 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  365. }
  366. }
  367. func TestDeleteRuleDoesNotExist(t *testing.T) {
  368. fcmd := fakeexec.FakeCmd{
  369. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  370. // iptables version check
  371. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  372. // iptables-restore version check
  373. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  374. // Status 1 on the first call.
  375. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  376. },
  377. }
  378. fexec := fakeexec.FakeExec{
  379. CommandScript: []fakeexec.FakeCommandAction{
  380. // iptables version check
  381. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  382. // iptables-restore version check
  383. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  384. // The second Command() call is checking the rule. Failure of that exec means "does not exist".
  385. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  386. },
  387. }
  388. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  389. defer runner.Destroy()
  390. err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
  391. if err != nil {
  392. t.Errorf("expected success, got %v", err)
  393. }
  394. if fcmd.CombinedOutputCalls != 3 {
  395. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  396. }
  397. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
  398. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  399. }
  400. }
  401. func TestDeleteRuleExists(t *testing.T) {
  402. fcmd := fakeexec.FakeCmd{
  403. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  404. // iptables version check
  405. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  406. // iptables-restore version check
  407. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  408. // Success on the first call.
  409. func() ([]byte, error) { return []byte{}, nil },
  410. // Success on the second call.
  411. func() ([]byte, error) { return []byte{}, nil },
  412. },
  413. }
  414. fexec := fakeexec.FakeExec{
  415. CommandScript: []fakeexec.FakeCommandAction{
  416. // iptables version check
  417. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  418. // iptables-restore version check
  419. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  420. // The second Command() call is checking the rule. Success of that means delete it.
  421. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  422. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  423. },
  424. }
  425. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  426. defer runner.Destroy()
  427. err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
  428. if err != nil {
  429. t.Errorf("expected success, got %v", err)
  430. }
  431. if fcmd.CombinedOutputCalls != 4 {
  432. t.Errorf("expected 4 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  433. }
  434. if !sets.NewString(fcmd.CombinedOutputLog[3]...).HasAll("iptables", "-t", "nat", "-D", "OUTPUT", "abc", "123") {
  435. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[3])
  436. }
  437. }
  438. func TestDeleteRuleErrorChecking(t *testing.T) {
  439. fcmd := fakeexec.FakeCmd{
  440. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  441. // iptables version check
  442. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  443. // iptables-restore version check
  444. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  445. // Status 2 on the first call.
  446. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 2} },
  447. },
  448. }
  449. fexec := fakeexec.FakeExec{
  450. CommandScript: []fakeexec.FakeCommandAction{
  451. // iptables version check
  452. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  453. // iptables-restore version check
  454. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  455. // The second Command() call is checking the rule. Failure of that means create it.
  456. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  457. },
  458. }
  459. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  460. defer runner.Destroy()
  461. err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
  462. if err == nil {
  463. t.Errorf("expected failure")
  464. }
  465. if fcmd.CombinedOutputCalls != 3 {
  466. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  467. }
  468. }
  469. func TestDeleteRuleErrorDeleting(t *testing.T) {
  470. fcmd := fakeexec.FakeCmd{
  471. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  472. // iptables version check
  473. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  474. // iptables-restore version check
  475. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  476. // Success on the first call.
  477. func() ([]byte, error) { return []byte{}, nil },
  478. // Status 1 on the second call.
  479. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  480. },
  481. }
  482. fexec := fakeexec.FakeExec{
  483. CommandScript: []fakeexec.FakeCommandAction{
  484. // iptables version check
  485. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  486. // iptables-restore version check
  487. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  488. // The second Command() call is checking the rule. Success of that means delete it.
  489. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  490. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  491. },
  492. }
  493. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  494. defer runner.Destroy()
  495. err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
  496. if err == nil {
  497. t.Errorf("expected failure")
  498. }
  499. if fcmd.CombinedOutputCalls != 4 {
  500. t.Errorf("expected 4 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  501. }
  502. }
  503. func TestGetIPTablesHasCheckCommand(t *testing.T) {
  504. testCases := []struct {
  505. Version string
  506. Err bool
  507. Expected bool
  508. }{
  509. {"iptables v1.4.7", false, false},
  510. {"iptables v1.4.11", false, true},
  511. {"iptables v1.4.19.1", false, true},
  512. {"iptables v2.0.0", false, true},
  513. {"total junk", true, false},
  514. }
  515. for _, testCase := range testCases {
  516. fcmd := fakeexec.FakeCmd{
  517. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  518. func() ([]byte, error) { return []byte(testCase.Version), nil },
  519. },
  520. }
  521. fexec := fakeexec.FakeExec{
  522. CommandScript: []fakeexec.FakeCommandAction{
  523. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  524. },
  525. }
  526. version, err := getIPTablesVersionString(&fexec, ProtocolIpv4)
  527. if (err != nil) != testCase.Err {
  528. t.Errorf("Expected error: %v, Got error: %v", testCase.Err, err)
  529. }
  530. if err == nil {
  531. check := getIPTablesHasCheckCommand(version)
  532. if testCase.Expected != check {
  533. t.Errorf("Expected result: %v, Got result: %v", testCase.Expected, check)
  534. }
  535. }
  536. }
  537. }
  538. func TestIPTablesCommands(t *testing.T) {
  539. testCases := []struct {
  540. funcName string
  541. protocol Protocol
  542. expectedCmd string
  543. }{
  544. {"iptablesCommand", ProtocolIpv4, cmdIPTables},
  545. {"iptablesCommand", ProtocolIpv6, cmdIP6Tables},
  546. {"iptablesSaveCommand", ProtocolIpv4, cmdIPTablesSave},
  547. {"iptablesSaveCommand", ProtocolIpv6, cmdIP6TablesSave},
  548. {"iptablesRestoreCommand", ProtocolIpv4, cmdIPTablesRestore},
  549. {"iptablesRestoreCommand", ProtocolIpv6, cmdIP6TablesRestore},
  550. }
  551. for _, testCase := range testCases {
  552. var cmd string
  553. switch testCase.funcName {
  554. case "iptablesCommand":
  555. cmd = iptablesCommand(testCase.protocol)
  556. case "iptablesSaveCommand":
  557. cmd = iptablesSaveCommand(testCase.protocol)
  558. case "iptablesRestoreCommand":
  559. cmd = iptablesRestoreCommand(testCase.protocol)
  560. }
  561. if cmd != testCase.expectedCmd {
  562. t.Errorf("Function: %s, Expected result: %s, Actual result: %s", testCase.funcName, testCase.expectedCmd, cmd)
  563. }
  564. }
  565. }
  566. func TestCheckRuleWithoutCheckPresent(t *testing.T) {
  567. iptablesSaveOutput := `# Generated by iptables-save v1.4.7 on Wed Oct 29 14:56:01 2014
  568. *nat
  569. :PREROUTING ACCEPT [2136997:197881818]
  570. :POSTROUTING ACCEPT [4284525:258542680]
  571. :OUTPUT ACCEPT [5901660:357267963]
  572. -A PREROUTING -m addrtype --dst-type LOCAL -m mark --mark 0x00004000/0x00004000 -j DOCKER
  573. COMMIT
  574. # Completed on Wed Oct 29 14:56:01 2014`
  575. fcmd := fakeexec.FakeCmd{
  576. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  577. // Success.
  578. func() ([]byte, error) { return []byte(iptablesSaveOutput), nil },
  579. },
  580. }
  581. fexec := fakeexec.FakeExec{
  582. CommandScript: []fakeexec.FakeCommandAction{
  583. // The first Command() call is checking the rule. Success of that exec means "done".
  584. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  585. },
  586. }
  587. runner := &runner{exec: &fexec}
  588. exists, err := runner.checkRuleWithoutCheck(
  589. TableNAT, ChainPrerouting,
  590. "-m", "addrtype",
  591. "-m", "mark", "--mark", "0x4000/0x4000",
  592. "-j", "DOCKER",
  593. "--dst-type", "LOCAL")
  594. if err != nil {
  595. t.Errorf("expected success, got %v", err)
  596. }
  597. if !exists {
  598. t.Errorf("expected exists = true")
  599. }
  600. if fcmd.CombinedOutputCalls != 1 {
  601. t.Errorf("expected 1 CombinedOutput() call, got %d", fcmd.CombinedOutputCalls)
  602. }
  603. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("iptables-save", "-t", "nat") {
  604. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  605. }
  606. }
  607. func TestCheckRuleWithoutCheckAbsent(t *testing.T) {
  608. iptablesSaveOutput := `# Generated by iptables-save v1.4.7 on Wed Oct 29 14:56:01 2014
  609. *nat
  610. :PREROUTING ACCEPT [2136997:197881818]
  611. :POSTROUTING ACCEPT [4284525:258542680]
  612. :OUTPUT ACCEPT [5901660:357267963]
  613. -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
  614. COMMIT
  615. # Completed on Wed Oct 29 14:56:01 2014`
  616. fcmd := fakeexec.FakeCmd{
  617. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  618. // Success.
  619. func() ([]byte, error) { return []byte(iptablesSaveOutput), nil },
  620. },
  621. }
  622. fexec := fakeexec.FakeExec{
  623. CommandScript: []fakeexec.FakeCommandAction{
  624. // The first Command() call is checking the rule. Success of that exec means "done".
  625. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  626. },
  627. }
  628. runner := &runner{exec: &fexec}
  629. exists, err := runner.checkRuleWithoutCheck(TableNAT, ChainPrerouting, "-m", "addrtype", "-j", "DOCKER")
  630. if err != nil {
  631. t.Errorf("expected success, got %v", err)
  632. }
  633. if exists {
  634. t.Errorf("expected exists = false")
  635. }
  636. if fcmd.CombinedOutputCalls != 1 {
  637. t.Errorf("expected 1 CombinedOutput() call, got %d", fcmd.CombinedOutputCalls)
  638. }
  639. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("iptables-save", "-t", "nat") {
  640. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  641. }
  642. }
  643. func TestIPTablesWaitFlag(t *testing.T) {
  644. testCases := []struct {
  645. Version string
  646. Result []string
  647. }{
  648. {"0.55.55", nil},
  649. {"1.0.55", nil},
  650. {"1.4.19", nil},
  651. {"1.4.20", []string{WaitString}},
  652. {"1.4.21", []string{WaitString}},
  653. {"1.4.22", []string{WaitString, WaitSecondsValue}},
  654. {"1.5.0", []string{WaitString, WaitSecondsValue}},
  655. {"2.0.0", []string{WaitString, WaitSecondsValue}},
  656. }
  657. for _, testCase := range testCases {
  658. result := getIPTablesWaitFlag(testCase.Version)
  659. if !reflect.DeepEqual(result, testCase.Result) {
  660. t.Errorf("For %s expected %v got %v", testCase.Version, testCase.Result, result)
  661. }
  662. }
  663. }
  664. func TestWaitFlagUnavailable(t *testing.T) {
  665. fcmd := fakeexec.FakeCmd{
  666. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  667. // iptables version check
  668. func() ([]byte, error) { return []byte("iptables v1.4.19"), nil },
  669. // iptables-restore version check
  670. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  671. // Success.
  672. func() ([]byte, error) { return []byte{}, nil },
  673. },
  674. }
  675. fexec := fakeexec.FakeExec{
  676. CommandScript: []fakeexec.FakeCommandAction{
  677. // iptables version check
  678. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  679. // iptables-restore version check
  680. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  681. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  682. },
  683. }
  684. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  685. defer runner.Destroy()
  686. err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
  687. if err != nil {
  688. t.Errorf("expected success, got %v", err)
  689. }
  690. if fcmd.CombinedOutputCalls != 3 {
  691. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  692. }
  693. if sets.NewString(fcmd.CombinedOutputLog[2]...).Has(WaitString) {
  694. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  695. }
  696. }
  697. func TestWaitFlagOld(t *testing.T) {
  698. fcmd := fakeexec.FakeCmd{
  699. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  700. // iptables version check
  701. func() ([]byte, error) { return []byte("iptables v1.4.20"), nil },
  702. // iptables-restore version check
  703. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  704. // Success.
  705. func() ([]byte, error) { return []byte{}, nil },
  706. },
  707. }
  708. fexec := fakeexec.FakeExec{
  709. CommandScript: []fakeexec.FakeCommandAction{
  710. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  711. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  712. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  713. },
  714. }
  715. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  716. defer runner.Destroy()
  717. err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
  718. if err != nil {
  719. t.Errorf("expected success, got %v", err)
  720. }
  721. if fcmd.CombinedOutputCalls != 3 {
  722. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  723. }
  724. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", WaitString) {
  725. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  726. }
  727. if sets.NewString(fcmd.CombinedOutputLog[2]...).Has(WaitSecondsValue) {
  728. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  729. }
  730. }
  731. func TestWaitFlagNew(t *testing.T) {
  732. fcmd := fakeexec.FakeCmd{
  733. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  734. // iptables version check
  735. func() ([]byte, error) { return []byte("iptables v1.4.22"), nil },
  736. // iptables-restore version check
  737. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  738. // Success.
  739. func() ([]byte, error) { return []byte{}, nil },
  740. },
  741. }
  742. fexec := fakeexec.FakeExec{
  743. CommandScript: []fakeexec.FakeCommandAction{
  744. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  745. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  746. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  747. },
  748. }
  749. runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
  750. defer runner.Destroy()
  751. err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
  752. if err != nil {
  753. t.Errorf("expected success, got %v", err)
  754. }
  755. if fcmd.CombinedOutputCalls != 3 {
  756. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  757. }
  758. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", WaitString, WaitSecondsValue) {
  759. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  760. }
  761. }
  762. func TestReload(t *testing.T) {
  763. dbusConn := dbus.NewFakeConnection()
  764. dbusConn.SetBusObject(func(method string, args ...interface{}) ([]interface{}, error) { return nil, nil })
  765. dbusConn.AddObject(firewalldName, firewalldPath, func(method string, args ...interface{}) ([]interface{}, error) { return nil, nil })
  766. fdbus := dbus.NewFake(dbusConn, nil)
  767. reloaded := make(chan bool, 2)
  768. fcmd := fakeexec.FakeCmd{
  769. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  770. // iptables version check
  771. func() ([]byte, error) { return []byte("iptables v1.4.22"), nil },
  772. // iptables-restore version check
  773. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  774. // first reload
  775. // EnsureChain
  776. func() ([]byte, error) { return []byte{}, nil },
  777. // EnsureRule abc check
  778. func() ([]byte, error) { return []byte{}, &fakeexec.FakeExitError{Status: 1} },
  779. // EnsureRule abc
  780. func() ([]byte, error) { return []byte{}, nil },
  781. // second reload
  782. // EnsureChain
  783. func() ([]byte, error) { return []byte{}, nil },
  784. // EnsureRule abc check
  785. func() ([]byte, error) { return []byte{}, &fakeexec.FakeExitError{Status: 1} },
  786. // EnsureRule abc
  787. func() ([]byte, error) { return []byte{}, nil },
  788. },
  789. }
  790. fexec := fakeexec.FakeExec{
  791. CommandScript: []fakeexec.FakeCommandAction{
  792. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  793. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  794. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  795. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  796. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  797. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  798. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  799. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  800. },
  801. }
  802. runner := New(&fexec, fdbus, ProtocolIpv4)
  803. defer runner.Destroy()
  804. runner.AddReloadFunc(func() {
  805. exists, err := runner.EnsureChain(TableNAT, Chain("FOOBAR"))
  806. if err != nil {
  807. t.Errorf("expected success, got %v", err)
  808. }
  809. if exists {
  810. t.Errorf("expected exists = false")
  811. }
  812. reloaded <- true
  813. })
  814. runner.AddReloadFunc(func() {
  815. exists, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
  816. if err != nil {
  817. t.Errorf("expected success, got %v", err)
  818. }
  819. if exists {
  820. t.Errorf("expected exists = false")
  821. }
  822. reloaded <- true
  823. })
  824. dbusConn.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", firewalldName, "", ":1.1")
  825. <-reloaded
  826. <-reloaded
  827. if fcmd.CombinedOutputCalls != 5 {
  828. t.Errorf("expected 5 CombinedOutput() calls total, got %d", fcmd.CombinedOutputCalls)
  829. }
  830. if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-N", "FOOBAR") {
  831. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  832. }
  833. if !sets.NewString(fcmd.CombinedOutputLog[3]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
  834. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[3])
  835. }
  836. if !sets.NewString(fcmd.CombinedOutputLog[4]...).HasAll("iptables", "-t", "nat", "-A", "OUTPUT", "abc", "123") {
  837. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[4])
  838. }
  839. go func() { time.Sleep(time.Second / 100); reloaded <- true }()
  840. dbusConn.EmitSignal(firewalldName, firewalldPath, firewalldInterface, "DefaultZoneChanged", "public")
  841. dbusConn.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "io.k8s.Something", "", ":1.1")
  842. <-reloaded
  843. if fcmd.CombinedOutputCalls != 5 {
  844. t.Errorf("Incorrect signal caused a reload")
  845. }
  846. dbusConn.EmitSignal(firewalldName, firewalldPath, firewalldInterface, "Reloaded")
  847. <-reloaded
  848. <-reloaded
  849. if fcmd.CombinedOutputCalls != 8 {
  850. t.Errorf("expected 8 CombinedOutput() calls total, got %d", fcmd.CombinedOutputCalls)
  851. }
  852. if !sets.NewString(fcmd.CombinedOutputLog[5]...).HasAll("iptables", "-t", "nat", "-N", "FOOBAR") {
  853. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[5])
  854. }
  855. if !sets.NewString(fcmd.CombinedOutputLog[6]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
  856. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[6])
  857. }
  858. if !sets.NewString(fcmd.CombinedOutputLog[7]...).HasAll("iptables", "-t", "nat", "-A", "OUTPUT", "abc", "123") {
  859. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[7])
  860. }
  861. }
  862. func testSaveInto(t *testing.T, protocol Protocol) {
  863. version := " v1.9.22"
  864. iptablesCmd := iptablesCommand(protocol)
  865. iptablesSaveCmd := iptablesSaveCommand(protocol)
  866. iptablesRestoreCmd := iptablesRestoreCommand(protocol)
  867. protoStr := protocolStr(protocol)
  868. output := fmt.Sprintf(`# Generated by %s on Thu Jan 19 11:38:09 2017
  869. *filter
  870. :INPUT ACCEPT [15079:38410730]
  871. :FORWARD ACCEPT [0:0]
  872. :OUTPUT ACCEPT [11045:521562]
  873. COMMIT
  874. # Completed on Thu Jan 19 11:38:09 2017`, iptablesSaveCmd+version)
  875. stderrOutput := "#STDERR OUTPUT" // SaveInto() should should NOT capture stderr into the buffer
  876. fcmd := fakeexec.FakeCmd{
  877. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  878. // iptables version check
  879. func() ([]byte, error) { return []byte(iptablesCmd + version), nil },
  880. // iptables-restore version check
  881. func() ([]byte, error) { return []byte(iptablesRestoreCmd + version), nil },
  882. },
  883. RunScript: []fakeexec.FakeRunAction{
  884. func() ([]byte, []byte, error) { return []byte(output), []byte(stderrOutput), nil },
  885. func() ([]byte, []byte, error) { return nil, []byte(stderrOutput), &fakeexec.FakeExitError{Status: 1} },
  886. },
  887. }
  888. fexec := fakeexec.FakeExec{
  889. CommandScript: []fakeexec.FakeCommandAction{
  890. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  891. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  892. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  893. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  894. },
  895. }
  896. runner := New(&fexec, dbus.NewFake(nil, nil), protocol)
  897. defer runner.Destroy()
  898. buffer := bytes.NewBuffer(nil)
  899. // Success.
  900. err := runner.SaveInto(TableNAT, buffer)
  901. if err != nil {
  902. t.Fatalf("%s: Expected success, got %v", protoStr, err)
  903. }
  904. if string(buffer.Bytes()) != output {
  905. t.Errorf("%s: Expected output '%s', got '%v'", protoStr, output, string(buffer.Bytes()))
  906. }
  907. if fcmd.CombinedOutputCalls != 2 {
  908. t.Errorf("%s: Expected 2 CombinedOutput() calls, got %d", protoStr, fcmd.CombinedOutputCalls)
  909. }
  910. if fcmd.RunCalls != 1 {
  911. t.Errorf("%s: Expected 1 Run() call, got %d", protoStr, fcmd.RunCalls)
  912. }
  913. if !sets.NewString(fcmd.RunLog[0]...).HasAll(iptablesSaveCmd, "-t", "nat") {
  914. t.Errorf("%s: Expected cmd containing '%s -t nat', got '%s'", protoStr, iptablesSaveCmd, fcmd.RunLog[0])
  915. }
  916. // Failure.
  917. buffer.Reset()
  918. err = runner.SaveInto(TableNAT, buffer)
  919. if err == nil {
  920. t.Errorf("%s: Expected failure", protoStr)
  921. }
  922. if string(buffer.Bytes()) != stderrOutput {
  923. t.Errorf("%s: Expected output '%s', got '%v'", protoStr, stderrOutput, string(buffer.Bytes()))
  924. }
  925. }
  926. func TestSaveIntoIPv4(t *testing.T) {
  927. testSaveInto(t, ProtocolIpv4)
  928. }
  929. func TestSaveIntoIPv6(t *testing.T) {
  930. testSaveInto(t, ProtocolIpv6)
  931. }
  932. func testRestore(t *testing.T, protocol Protocol) {
  933. version := " v1.9.22"
  934. iptablesCmd := iptablesCommand(protocol)
  935. iptablesRestoreCmd := iptablesRestoreCommand(protocol)
  936. protoStr := protocolStr(protocol)
  937. fcmd := fakeexec.FakeCmd{
  938. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  939. // iptables version check
  940. func() ([]byte, error) { return []byte(iptablesCmd + version), nil },
  941. // iptables-restore version check
  942. func() ([]byte, error) { return []byte(iptablesRestoreCmd + version), nil },
  943. func() ([]byte, error) { return []byte{}, nil },
  944. func() ([]byte, error) { return []byte{}, nil },
  945. func() ([]byte, error) { return []byte{}, nil },
  946. func() ([]byte, error) { return []byte{}, nil },
  947. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  948. },
  949. }
  950. fexec := fakeexec.FakeExec{
  951. CommandScript: []fakeexec.FakeCommandAction{
  952. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  953. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  954. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  955. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  956. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  957. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  958. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  959. },
  960. }
  961. runner := New(&fexec, dbus.NewFake(nil, nil), protocol)
  962. defer runner.Destroy()
  963. // both flags true
  964. err := runner.Restore(TableNAT, []byte{}, FlushTables, RestoreCounters)
  965. if err != nil {
  966. t.Errorf("%s flush,restore: Expected success, got %v", protoStr, err)
  967. }
  968. commandSet := sets.NewString(fcmd.CombinedOutputLog[2]...)
  969. if !commandSet.HasAll(iptablesRestoreCmd, "-T", string(TableNAT), "--counters") || commandSet.HasAny("--noflush") {
  970. t.Errorf("%s flush, restore: Expected cmd containing '%s -T %s --counters', got '%s'", protoStr, iptablesRestoreCmd, string(TableNAT), fcmd.CombinedOutputLog[2])
  971. }
  972. // FlushTables, NoRestoreCounters
  973. err = runner.Restore(TableNAT, []byte{}, FlushTables, NoRestoreCounters)
  974. if err != nil {
  975. t.Errorf("%s flush, no restore: Expected success, got %v", protoStr, err)
  976. }
  977. commandSet = sets.NewString(fcmd.CombinedOutputLog[3]...)
  978. if !commandSet.HasAll(iptablesRestoreCmd, "-T", string(TableNAT)) || commandSet.HasAny("--noflush", "--counters") {
  979. t.Errorf("%s flush, no restore: Expected cmd containing '--noflush' or '--counters', got '%s'", protoStr, fcmd.CombinedOutputLog[3])
  980. }
  981. // NoFlushTables, RestoreCounters
  982. err = runner.Restore(TableNAT, []byte{}, NoFlushTables, RestoreCounters)
  983. if err != nil {
  984. t.Errorf("%s no flush, restore: Expected success, got %v", protoStr, err)
  985. }
  986. commandSet = sets.NewString(fcmd.CombinedOutputLog[4]...)
  987. if !commandSet.HasAll(iptablesRestoreCmd, "-T", string(TableNAT), "--noflush", "--counters") {
  988. t.Errorf("%s no flush, restore: Expected cmd containing '--noflush' and '--counters', got '%s'", protoStr, fcmd.CombinedOutputLog[4])
  989. }
  990. // NoFlushTables, NoRestoreCounters
  991. err = runner.Restore(TableNAT, []byte{}, NoFlushTables, NoRestoreCounters)
  992. if err != nil {
  993. t.Errorf("%s no flush, no restore: Expected success, got %v", protoStr, err)
  994. }
  995. commandSet = sets.NewString(fcmd.CombinedOutputLog[5]...)
  996. if !commandSet.HasAll(iptablesRestoreCmd, "-T", string(TableNAT), "--noflush") || commandSet.HasAny("--counters") {
  997. t.Errorf("%s no flush, no restore: Expected cmd containing '%s -T %s --noflush', got '%s'", protoStr, iptablesRestoreCmd, string(TableNAT), fcmd.CombinedOutputLog[5])
  998. }
  999. if fcmd.CombinedOutputCalls != 6 {
  1000. t.Errorf("%s: Expected 6 total CombinedOutput() calls, got %d", protoStr, fcmd.CombinedOutputCalls)
  1001. }
  1002. // Failure.
  1003. err = runner.Restore(TableNAT, []byte{}, FlushTables, RestoreCounters)
  1004. if err == nil {
  1005. t.Errorf("%s Expected a failure", protoStr)
  1006. }
  1007. }
  1008. func TestRestoreIPv4(t *testing.T) {
  1009. testRestore(t, ProtocolIpv4)
  1010. }
  1011. func TestRestoreIPv6(t *testing.T) {
  1012. testRestore(t, ProtocolIpv6)
  1013. }
  1014. // TestRestoreAll tests only the simplest use case, as flag handling code is already tested in TestRestore
  1015. func TestRestoreAll(t *testing.T) {
  1016. fcmd := fakeexec.FakeCmd{
  1017. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  1018. // iptables version check
  1019. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  1020. // iptables-restore version check
  1021. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  1022. func() ([]byte, error) { return []byte{}, nil },
  1023. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  1024. },
  1025. }
  1026. fexec := fakeexec.FakeExec{
  1027. CommandScript: []fakeexec.FakeCommandAction{
  1028. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1029. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1030. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1031. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1032. },
  1033. }
  1034. runner := newInternal(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4, TestLockfilePath)
  1035. defer os.Remove(TestLockfilePath)
  1036. defer runner.Destroy()
  1037. err := runner.RestoreAll([]byte{}, NoFlushTables, RestoreCounters)
  1038. if err != nil {
  1039. t.Fatalf("expected success, got %v", err)
  1040. }
  1041. commandSet := sets.NewString(fcmd.CombinedOutputLog[2]...)
  1042. if !commandSet.HasAll("iptables-restore", "--counters", "--noflush") {
  1043. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  1044. }
  1045. if fcmd.CombinedOutputCalls != 3 {
  1046. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  1047. }
  1048. // Failure.
  1049. err = runner.Restore(TableNAT, []byte{}, FlushTables, RestoreCounters)
  1050. if err == nil {
  1051. t.Errorf("expected failure")
  1052. }
  1053. }
  1054. // TestRestoreAllWait tests that the "wait" flag is passed to a compatible iptables-restore
  1055. func TestRestoreAllWait(t *testing.T) {
  1056. fcmd := fakeexec.FakeCmd{
  1057. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  1058. // iptables version check
  1059. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  1060. // iptables-restore version check
  1061. func() ([]byte, error) { return []byte("iptables-restore v1.9.22"), nil },
  1062. func() ([]byte, error) { return []byte{}, nil },
  1063. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  1064. },
  1065. }
  1066. fexec := fakeexec.FakeExec{
  1067. CommandScript: []fakeexec.FakeCommandAction{
  1068. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1069. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1070. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1071. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1072. },
  1073. }
  1074. runner := newInternal(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4, TestLockfilePath)
  1075. defer os.Remove(TestLockfilePath)
  1076. defer runner.Destroy()
  1077. err := runner.RestoreAll([]byte{}, NoFlushTables, RestoreCounters)
  1078. if err != nil {
  1079. t.Fatalf("expected success, got %v", err)
  1080. }
  1081. commandSet := sets.NewString(fcmd.CombinedOutputLog[2]...)
  1082. if !commandSet.HasAll("iptables-restore", WaitString, WaitSecondsValue, "--counters", "--noflush") {
  1083. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  1084. }
  1085. if fcmd.CombinedOutputCalls != 3 {
  1086. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  1087. }
  1088. // Failure.
  1089. err = runner.Restore(TableNAT, []byte{}, FlushTables, RestoreCounters)
  1090. if err == nil {
  1091. t.Errorf("expected failure")
  1092. }
  1093. }
  1094. // TestRestoreAllWaitOldIptablesRestore tests that the "wait" flag is not passed
  1095. // to a in-compatible iptables-restore
  1096. func TestRestoreAllWaitOldIptablesRestore(t *testing.T) {
  1097. fcmd := fakeexec.FakeCmd{
  1098. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  1099. // iptables version check
  1100. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  1101. // iptables-restore version check
  1102. func() ([]byte, error) { return []byte("unrecognized option: --version"), nil },
  1103. func() ([]byte, error) { return []byte{}, nil },
  1104. func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
  1105. },
  1106. }
  1107. fexec := fakeexec.FakeExec{
  1108. CommandScript: []fakeexec.FakeCommandAction{
  1109. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1110. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1111. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1112. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1113. },
  1114. }
  1115. runner := newInternal(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4, TestLockfilePath)
  1116. defer os.Remove(TestLockfilePath)
  1117. defer runner.Destroy()
  1118. err := runner.RestoreAll([]byte{}, NoFlushTables, RestoreCounters)
  1119. if err != nil {
  1120. t.Fatalf("expected success, got %v", err)
  1121. }
  1122. commandSet := sets.NewString(fcmd.CombinedOutputLog[2]...)
  1123. if !commandSet.HasAll("iptables-restore", "--counters", "--noflush") {
  1124. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
  1125. }
  1126. if commandSet.HasAll(WaitString, WaitSecondsValue) {
  1127. t.Errorf("wrong CombinedOutput() log (unexpected %s option), got %s", WaitString, fcmd.CombinedOutputLog[2])
  1128. }
  1129. if fcmd.CombinedOutputCalls != 3 {
  1130. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  1131. }
  1132. // Failure.
  1133. err = runner.Restore(TableNAT, []byte{}, FlushTables, RestoreCounters)
  1134. if err == nil {
  1135. t.Errorf("expected failure")
  1136. }
  1137. }
  1138. // TestRestoreAllGrabNewLock tests that the iptables code will grab the
  1139. // iptables /run lock when using an iptables-restore version that does not
  1140. // support the --wait argument
  1141. func TestRestoreAllGrabNewLock(t *testing.T) {
  1142. fcmd := fakeexec.FakeCmd{
  1143. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  1144. // iptables version check
  1145. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  1146. // iptables-restore version check
  1147. func() ([]byte, error) { return []byte("unrecognized option: --version"), nil },
  1148. },
  1149. }
  1150. fexec := fakeexec.FakeExec{
  1151. CommandScript: []fakeexec.FakeCommandAction{
  1152. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1153. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1154. },
  1155. }
  1156. runner := newInternal(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4, TestLockfilePath)
  1157. defer os.Remove(TestLockfilePath)
  1158. defer runner.Destroy()
  1159. // Grab the /run lock and ensure the RestoreAll fails
  1160. runLock, err := os.OpenFile(TestLockfilePath, os.O_CREATE, 0600)
  1161. if err != nil {
  1162. t.Fatalf("expected to open %s, got %v", TestLockfilePath, err)
  1163. }
  1164. defer runLock.Close()
  1165. if err := grabIptablesFileLock(runLock); err != nil {
  1166. t.Errorf("expected to lock %s, got %v", TestLockfilePath, err)
  1167. }
  1168. err = runner.RestoreAll([]byte{}, NoFlushTables, RestoreCounters)
  1169. if err == nil {
  1170. t.Errorf("expected failure, got success instead")
  1171. }
  1172. if !strings.Contains(err.Error(), "failed to acquire new iptables lock: timed out waiting for the condition") {
  1173. t.Errorf("expected timeout error, got %v", err)
  1174. }
  1175. }
  1176. // TestRestoreAllGrabOldLock tests that the iptables code will grab the
  1177. // iptables @xtables abstract unix socket lock when using an iptables-restore
  1178. // version that does not support the --wait argument
  1179. func TestRestoreAllGrabOldLock(t *testing.T) {
  1180. fcmd := fakeexec.FakeCmd{
  1181. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  1182. // iptables version check
  1183. func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
  1184. // iptables-restore version check
  1185. func() ([]byte, error) { return []byte("unrecognized option: --version"), nil },
  1186. },
  1187. }
  1188. fexec := fakeexec.FakeExec{
  1189. CommandScript: []fakeexec.FakeCommandAction{
  1190. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1191. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  1192. },
  1193. }
  1194. runner := newInternal(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4, TestLockfilePath)
  1195. defer os.Remove(TestLockfilePath)
  1196. defer runner.Destroy()
  1197. // Grab the abstract @xtables socket
  1198. runLock, err := net.ListenUnix("unix", &net.UnixAddr{Name: "@xtables", Net: "unix"})
  1199. if err != nil {
  1200. t.Fatalf("expected to lock @xtables, got %v", err)
  1201. }
  1202. defer runLock.Close()
  1203. err = runner.RestoreAll([]byte{}, NoFlushTables, RestoreCounters)
  1204. if err == nil {
  1205. t.Errorf("expected failure, got success instead")
  1206. }
  1207. if !strings.Contains(err.Error(), "failed to acquire old iptables lock: timed out waiting for the condition") {
  1208. t.Errorf("expected timeout error, got %v", err)
  1209. }
  1210. }