ipset_test.go 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package ipset
  14. import (
  15. "reflect"
  16. "testing"
  17. "k8s.io/apimachinery/pkg/util/sets"
  18. "k8s.io/utils/exec"
  19. fakeexec "k8s.io/utils/exec/testing"
  20. )
  21. func TestCheckIPSetVersion(t *testing.T) {
  22. testCases := []struct {
  23. vstring string
  24. Expect string
  25. Err bool
  26. }{
  27. {"ipset v4.0, protocol version: 4", "v4.0", false},
  28. {"ipset v5.1, protocol version: 5", "v5.1", false},
  29. {"ipset v6.0, protocol version: 6", "v6.0", false},
  30. {"ipset v6.1, protocol version: 6", "v6.1", false},
  31. {"ipset v6.19, protocol version: 6", "v6.19", false},
  32. {"total junk", "", true},
  33. }
  34. for i := range testCases {
  35. fcmd := fakeexec.FakeCmd{
  36. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  37. // ipset version response
  38. func() ([]byte, error) { return []byte(testCases[i].vstring), nil },
  39. },
  40. }
  41. fexec := fakeexec.FakeExec{
  42. CommandScript: []fakeexec.FakeCommandAction{
  43. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  44. },
  45. }
  46. gotVersion, err := getIPSetVersionString(&fexec)
  47. if (err != nil) != testCases[i].Err {
  48. t.Errorf("Expected error: %v, Got error: %v", testCases[i].Err, err)
  49. }
  50. if err == nil {
  51. if testCases[i].Expect != gotVersion {
  52. t.Errorf("Expected result: %v, Got result: %v", testCases[i].Expect, gotVersion)
  53. }
  54. }
  55. }
  56. }
  57. func TestFlushSet(t *testing.T) {
  58. fcmd := fakeexec.FakeCmd{
  59. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  60. // Success
  61. func() ([]byte, error) { return []byte{}, nil },
  62. // Success
  63. func() ([]byte, error) { return []byte{}, nil },
  64. },
  65. }
  66. fexec := fakeexec.FakeExec{
  67. CommandScript: []fakeexec.FakeCommandAction{
  68. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  69. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  70. },
  71. }
  72. runner := New(&fexec)
  73. // Success.
  74. err := runner.FlushSet("FOOBAR")
  75. if err != nil {
  76. t.Errorf("expected success, got %v", err)
  77. }
  78. if fcmd.CombinedOutputCalls != 1 {
  79. t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  80. }
  81. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "flush", "FOOBAR") {
  82. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  83. }
  84. // Flush again
  85. err = runner.FlushSet("FOOBAR")
  86. if err != nil {
  87. t.Errorf("expected success, got %v", err)
  88. }
  89. }
  90. func TestDestroySet(t *testing.T) {
  91. fcmd := fakeexec.FakeCmd{
  92. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  93. // Success
  94. func() ([]byte, error) { return []byte{}, nil },
  95. // Failure
  96. func() ([]byte, error) {
  97. return []byte("ipset v6.19: The set with the given name does not exist"), &fakeexec.FakeExitError{Status: 1}
  98. },
  99. },
  100. }
  101. fexec := fakeexec.FakeExec{
  102. CommandScript: []fakeexec.FakeCommandAction{
  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. },
  106. }
  107. runner := New(&fexec)
  108. // Success
  109. err := runner.DestroySet("FOOBAR")
  110. if err != nil {
  111. t.Errorf("expected success, got %v", err)
  112. }
  113. if fcmd.CombinedOutputCalls != 1 {
  114. t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  115. }
  116. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "destroy", "FOOBAR") {
  117. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  118. }
  119. // Failure
  120. err = runner.DestroySet("FOOBAR")
  121. if err == nil {
  122. t.Errorf("expected failure, got nil")
  123. }
  124. }
  125. func TestDestroyAllSets(t *testing.T) {
  126. fcmd := fakeexec.FakeCmd{
  127. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  128. // Success
  129. func() ([]byte, error) { return []byte{}, nil },
  130. // Success
  131. func() ([]byte, error) { return []byte{}, nil },
  132. },
  133. }
  134. fexec := fakeexec.FakeExec{
  135. CommandScript: []fakeexec.FakeCommandAction{
  136. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  137. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  138. },
  139. }
  140. runner := New(&fexec)
  141. // Success
  142. err := runner.DestroyAllSets()
  143. if err != nil {
  144. t.Errorf("expected success, got %v", err)
  145. }
  146. if fcmd.CombinedOutputCalls != 1 {
  147. t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  148. }
  149. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "destroy") {
  150. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  151. }
  152. // Success
  153. err = runner.DestroyAllSets()
  154. if err != nil {
  155. t.Errorf("Unexpected failure: %v", err)
  156. }
  157. }
  158. func TestCreateSet(t *testing.T) {
  159. testSet := IPSet{
  160. Name: "FOOBAR",
  161. SetType: HashIPPort,
  162. HashFamily: ProtocolFamilyIPV4,
  163. }
  164. fcmd := fakeexec.FakeCmd{
  165. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  166. // Success
  167. func() ([]byte, error) { return []byte{}, nil },
  168. // Success
  169. func() ([]byte, error) { return []byte{}, nil },
  170. // Failure
  171. func() ([]byte, error) {
  172. return []byte("ipset v6.19: Set cannot be created: set with the same name already exists"), &fakeexec.FakeExitError{Status: 1}
  173. },
  174. },
  175. }
  176. fexec := fakeexec.FakeExec{
  177. CommandScript: []fakeexec.FakeCommandAction{
  178. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  179. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  180. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  181. },
  182. }
  183. runner := New(&fexec)
  184. // Create with ignoreExistErr = false, expect success
  185. err := runner.CreateSet(&testSet, false)
  186. if err != nil {
  187. t.Errorf("expected success, got %v", err)
  188. }
  189. if fcmd.CombinedOutputCalls != 1 {
  190. t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  191. }
  192. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "create", "FOOBAR", "hash:ip,port", "family", "inet", "hashsize", "1024", "maxelem", "65536") {
  193. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  194. }
  195. // Create with ignoreExistErr = true, expect success
  196. err = runner.CreateSet(&testSet, true)
  197. if err != nil {
  198. t.Errorf("expected success, got %v", err)
  199. }
  200. if fcmd.CombinedOutputCalls != 2 {
  201. t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  202. }
  203. if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("ipset", "create", "FOOBAR", "hash:ip,port", "family", "inet", "hashsize", "1024", "maxelem", "65536", "-exist") {
  204. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
  205. }
  206. // Create with ignoreExistErr = false, expect failure
  207. err = runner.CreateSet(&testSet, false)
  208. if err == nil {
  209. t.Errorf("expected failure, got nil")
  210. }
  211. }
  212. var testCases = []struct {
  213. entry *Entry
  214. set *IPSet
  215. addCombinedOutputLog [][]string
  216. delCombinedOutputLog []string
  217. }{
  218. { // case 0
  219. entry: &Entry{
  220. IP: "192.168.1.1",
  221. Port: 53,
  222. Protocol: ProtocolUDP,
  223. SetType: HashIPPort,
  224. },
  225. set: &IPSet{
  226. Name: "ZERO",
  227. },
  228. addCombinedOutputLog: [][]string{
  229. {"ipset", "add", "ZERO", "192.168.1.1,udp:53"},
  230. {"ipset", "add", "ZERO", "192.168.1.1,udp:53", "-exist"},
  231. },
  232. delCombinedOutputLog: []string{"ipset", "del", "ZERO", "192.168.1.1,udp:53"},
  233. },
  234. { // case 1
  235. entry: &Entry{
  236. IP: "192.168.1.2",
  237. Port: 80,
  238. Protocol: ProtocolTCP,
  239. SetType: HashIPPort,
  240. },
  241. set: &IPSet{
  242. Name: "UN",
  243. },
  244. addCombinedOutputLog: [][]string{
  245. {"ipset", "add", "UN", "192.168.1.2,tcp:80"},
  246. {"ipset", "add", "UN", "192.168.1.2,tcp:80", "-exist"},
  247. },
  248. delCombinedOutputLog: []string{"ipset", "del", "UN", "192.168.1.2,tcp:80"},
  249. },
  250. { // case 2
  251. entry: &Entry{
  252. IP: "192.168.1.3",
  253. Port: 53,
  254. Protocol: ProtocolUDP,
  255. SetType: HashIPPortIP,
  256. IP2: "10.20.30.1",
  257. },
  258. set: &IPSet{
  259. Name: "DEUX",
  260. },
  261. addCombinedOutputLog: [][]string{
  262. {"ipset", "add", "DEUX", "192.168.1.3,udp:53,10.20.30.1"},
  263. {"ipset", "add", "DEUX", "192.168.1.3,udp:53,10.20.30.1", "-exist"},
  264. },
  265. delCombinedOutputLog: []string{"ipset", "del", "DEUX", "192.168.1.3,udp:53,10.20.30.1"},
  266. },
  267. { // case 3
  268. entry: &Entry{
  269. IP: "192.168.1.4",
  270. Port: 80,
  271. Protocol: ProtocolTCP,
  272. SetType: HashIPPortIP,
  273. IP2: "10.20.30.2",
  274. },
  275. set: &IPSet{
  276. Name: "TROIS",
  277. },
  278. addCombinedOutputLog: [][]string{
  279. {"ipset", "add", "TROIS", "192.168.1.4,tcp:80,10.20.30.2"},
  280. {"ipset", "add", "TROIS", "192.168.1.4,tcp:80,10.20.30.2", "-exist"},
  281. },
  282. delCombinedOutputLog: []string{"ipset", "del", "TROIS", "192.168.1.4,tcp:80,10.20.30.2"},
  283. },
  284. { // case 4
  285. entry: &Entry{
  286. IP: "192.168.1.5",
  287. Port: 53,
  288. Protocol: ProtocolUDP,
  289. SetType: HashIPPortNet,
  290. Net: "10.20.30.0/24",
  291. },
  292. set: &IPSet{
  293. Name: "QUATRE",
  294. },
  295. addCombinedOutputLog: [][]string{
  296. {"ipset", "add", "QUATRE", "192.168.1.5,udp:53,10.20.30.0/24"},
  297. {"ipset", "add", "QUATRE", "192.168.1.5,udp:53,10.20.30.0/24", "-exist"},
  298. },
  299. delCombinedOutputLog: []string{"ipset", "del", "QUATRE", "192.168.1.5,udp:53,10.20.30.0/24"},
  300. },
  301. { // case 5
  302. entry: &Entry{
  303. IP: "192.168.1.6",
  304. Port: 80,
  305. Protocol: ProtocolTCP,
  306. SetType: HashIPPortNet,
  307. Net: "10.20.40.0/24",
  308. },
  309. set: &IPSet{
  310. Name: "CINQ",
  311. },
  312. addCombinedOutputLog: [][]string{
  313. {"ipset", "add", "CINQ", "192.168.1.6,tcp:80,10.20.40.0/24"},
  314. {"ipset", "add", "CINQ", "192.168.1.6,tcp:80,10.20.40.0/24", "-exist"},
  315. },
  316. delCombinedOutputLog: []string{"ipset", "del", "CINQ", "192.168.1.6,tcp:80,10.20.40.0/24"},
  317. },
  318. { // case 6
  319. entry: &Entry{
  320. Port: 80,
  321. Protocol: ProtocolTCP,
  322. SetType: BitmapPort,
  323. },
  324. set: &IPSet{
  325. Name: "SIX",
  326. },
  327. addCombinedOutputLog: [][]string{
  328. {"ipset", "add", "SIX", "80"},
  329. {"ipset", "add", "SIX", "80", "-exist"},
  330. },
  331. delCombinedOutputLog: []string{"ipset", "del", "SIX", "80"},
  332. },
  333. { // case 7
  334. entry: &Entry{
  335. IP: "192.168.1.2",
  336. Port: 80,
  337. Protocol: ProtocolSCTP,
  338. SetType: HashIPPort,
  339. },
  340. set: &IPSet{
  341. Name: "SETTE",
  342. },
  343. addCombinedOutputLog: [][]string{
  344. {"ipset", "add", "SETTE", "192.168.1.2,sctp:80"},
  345. {"ipset", "add", "SETTE", "192.168.1.2,sctp:80", "-exist"},
  346. },
  347. delCombinedOutputLog: []string{"ipset", "del", "SETTE", "192.168.1.2,sctp:80"},
  348. },
  349. }
  350. func TestAddEntry(t *testing.T) {
  351. for i := range testCases {
  352. fcmd := fakeexec.FakeCmd{
  353. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  354. // Success
  355. func() ([]byte, error) { return []byte{}, nil },
  356. // Success
  357. func() ([]byte, error) { return []byte{}, nil },
  358. // Failure
  359. func() ([]byte, error) {
  360. return []byte("ipset v6.19: Set cannot be created: set with the same name already exists"), &fakeexec.FakeExitError{Status: 1}
  361. },
  362. },
  363. }
  364. fexec := fakeexec.FakeExec{
  365. CommandScript: []fakeexec.FakeCommandAction{
  366. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  367. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  368. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  369. },
  370. }
  371. runner := New(&fexec)
  372. // Create with ignoreExistErr = false, expect success
  373. err := runner.AddEntry(testCases[i].entry.String(), testCases[i].set, false)
  374. if err != nil {
  375. t.Errorf("expected success, got %v", err)
  376. }
  377. if fcmd.CombinedOutputCalls != 1 {
  378. t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  379. }
  380. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll(testCases[i].addCombinedOutputLog[0]...) {
  381. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  382. }
  383. // Create with ignoreExistErr = true, expect success
  384. err = runner.AddEntry(testCases[i].entry.String(), testCases[i].set, true)
  385. if err != nil {
  386. t.Errorf("expected success, got %v", err)
  387. }
  388. if fcmd.CombinedOutputCalls != 2 {
  389. t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  390. }
  391. if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll(testCases[i].addCombinedOutputLog[1]...) {
  392. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
  393. }
  394. // Create with ignoreExistErr = false, expect failure
  395. err = runner.AddEntry(testCases[i].entry.String(), testCases[i].set, false)
  396. if err == nil {
  397. t.Errorf("expected failure, got nil")
  398. }
  399. }
  400. }
  401. func TestDelEntry(t *testing.T) {
  402. for i := range testCases {
  403. fcmd := fakeexec.FakeCmd{
  404. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  405. // Success
  406. func() ([]byte, error) { return []byte{}, nil },
  407. // Failure
  408. func() ([]byte, error) {
  409. return []byte("ipset v6.19: Element cannot be deleted from the set: it's not added"), &fakeexec.FakeExitError{Status: 1}
  410. },
  411. },
  412. }
  413. fexec := fakeexec.FakeExec{
  414. CommandScript: []fakeexec.FakeCommandAction{
  415. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  416. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  417. },
  418. }
  419. runner := New(&fexec)
  420. err := runner.DelEntry(testCases[i].entry.String(), testCases[i].set.Name)
  421. if err != nil {
  422. t.Errorf("expected success, got %v", err)
  423. }
  424. if fcmd.CombinedOutputCalls != 1 {
  425. t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  426. }
  427. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll(testCases[i].delCombinedOutputLog...) {
  428. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  429. }
  430. err = runner.DelEntry(testCases[i].entry.String(), testCases[i].set.Name)
  431. if err == nil {
  432. t.Errorf("expected failure, got nil")
  433. }
  434. }
  435. }
  436. func TestTestEntry(t *testing.T) {
  437. // TODO: IPv6?
  438. testEntry := &Entry{
  439. IP: "10.120.7.100",
  440. Port: 8080,
  441. Protocol: ProtocolTCP,
  442. SetType: HashIPPort,
  443. }
  444. setName := "NOT"
  445. fcmd := fakeexec.FakeCmd{
  446. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  447. // Success
  448. func() ([]byte, error) { return []byte("10.120.7.100,tcp:8080 is in set " + setName + "."), nil },
  449. // Failure
  450. func() ([]byte, error) {
  451. return []byte("192.168.1.3,tcp:8080 is NOT in set " + setName + "."), &fakeexec.FakeExitError{Status: 1}
  452. },
  453. },
  454. }
  455. fexec := fakeexec.FakeExec{
  456. CommandScript: []fakeexec.FakeCommandAction{
  457. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  458. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  459. },
  460. }
  461. runner := New(&fexec)
  462. // Success
  463. ok, err := runner.TestEntry(testEntry.String(), setName)
  464. if err != nil {
  465. t.Errorf("expected success, got %v", err)
  466. }
  467. if fcmd.CombinedOutputCalls != 1 {
  468. t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
  469. }
  470. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "test", setName, "10.120.7.100,tcp:8080") {
  471. t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
  472. }
  473. if !ok {
  474. t.Errorf("expect entry exists in test set, got not")
  475. }
  476. // Failure
  477. ok, err = runner.TestEntry(testEntry.String(), "FOOBAR")
  478. if err == nil || ok {
  479. t.Errorf("expect entry doesn't exist in test set")
  480. }
  481. }
  482. func TestListEntries(t *testing.T) {
  483. output := `Name: foobar
  484. Type: hash:ip,port
  485. Revision: 2
  486. Header: family inet hashsize 1024 maxelem 65536
  487. Size in memory: 16592
  488. References: 0
  489. Members:
  490. 192.168.1.2,tcp:8080
  491. 192.168.1.1,udp:53`
  492. emptyOutput := `Name: KUBE-NODE-PORT
  493. Type: bitmap:port
  494. Revision: 1
  495. Header: range 0-65535
  496. Size in memory: 524432
  497. References: 1
  498. Members:
  499. `
  500. testCases := []struct {
  501. output string
  502. expected []string
  503. }{
  504. {
  505. output: output,
  506. expected: []string{"192.168.1.2,tcp:8080", "192.168.1.1,udp:53"},
  507. },
  508. {
  509. output: emptyOutput,
  510. expected: []string{},
  511. },
  512. }
  513. for i := range testCases {
  514. fcmd := fakeexec.FakeCmd{
  515. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  516. // Success
  517. func() ([]byte, error) {
  518. return []byte(testCases[i].output), nil
  519. },
  520. },
  521. }
  522. fexec := fakeexec.FakeExec{
  523. CommandScript: []fakeexec.FakeCommandAction{
  524. func(cmd string, args ...string) exec.Cmd {
  525. return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
  526. },
  527. },
  528. }
  529. runner := New(&fexec)
  530. // Success
  531. entries, err := runner.ListEntries("foobar")
  532. if err != nil {
  533. t.Errorf("expected success, got: %v", err)
  534. }
  535. if fcmd.CombinedOutputCalls != 1 {
  536. t.Errorf("expected 1 CombinedOutput() calls, got: %d", fcmd.CombinedOutputCalls)
  537. }
  538. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "list", "foobar") {
  539. t.Errorf("wrong CombinedOutput() log, got: %s", fcmd.CombinedOutputLog[0])
  540. }
  541. if len(entries) != len(testCases[i].expected) {
  542. t.Errorf("expected %d ipset entries, got: %d", len(testCases[i].expected), len(entries))
  543. }
  544. if !reflect.DeepEqual(entries, testCases[i].expected) {
  545. t.Errorf("expected entries: %v, got: %v", testCases[i].expected, entries)
  546. }
  547. }
  548. }
  549. func TestListSets(t *testing.T) {
  550. output := `foo
  551. bar
  552. baz`
  553. expected := []string{"foo", "bar", "baz"}
  554. fcmd := fakeexec.FakeCmd{
  555. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  556. // Success
  557. func() ([]byte, error) { return []byte(output), nil },
  558. },
  559. }
  560. fexec := fakeexec.FakeExec{
  561. CommandScript: []fakeexec.FakeCommandAction{
  562. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  563. },
  564. }
  565. runner := New(&fexec)
  566. // Success
  567. list, err := runner.ListSets()
  568. if err != nil {
  569. t.Errorf("expected success, got: %v", err)
  570. }
  571. if fcmd.CombinedOutputCalls != 1 {
  572. t.Errorf("expected 1 CombinedOutput() calls, got: %d", fcmd.CombinedOutputCalls)
  573. }
  574. if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ipset", "list", "-n") {
  575. t.Errorf("wrong CombinedOutput() log, got: %s", fcmd.CombinedOutputLog[0])
  576. }
  577. if len(list) != len(expected) {
  578. t.Errorf("expected %d sets, got: %d", len(expected), len(list))
  579. }
  580. if !reflect.DeepEqual(list, expected) {
  581. t.Errorf("expected sets: %v, got: %v", expected, list)
  582. }
  583. }
  584. func Test_validIPSetType(t *testing.T) {
  585. testCases := []struct {
  586. setType Type
  587. valid bool
  588. }{
  589. { // case[0]
  590. setType: Type("foo"),
  591. valid: false,
  592. },
  593. { // case[1]
  594. setType: HashIPPortNet,
  595. valid: true,
  596. },
  597. { // case[2]
  598. setType: HashIPPort,
  599. valid: true,
  600. },
  601. { // case[3]
  602. setType: HashIPPortIP,
  603. valid: true,
  604. },
  605. { // case[4]
  606. setType: BitmapPort,
  607. valid: true,
  608. },
  609. { // case[5]
  610. setType: Type(""),
  611. valid: false,
  612. },
  613. }
  614. for i := range testCases {
  615. valid := validateIPSetType(testCases[i].setType)
  616. if valid != testCases[i].valid {
  617. t.Errorf("case [%d]: unexpected mismatch, expect valid[%v], got valid[%v]", i, testCases[i].valid, valid)
  618. }
  619. }
  620. }
  621. func Test_validatePortRange(t *testing.T) {
  622. testCases := []struct {
  623. portRange string
  624. valid bool
  625. desc string
  626. }{
  627. { // case[0]
  628. portRange: "a-b",
  629. valid: false,
  630. desc: "invalid port number",
  631. },
  632. { // case[1]
  633. portRange: "1-2",
  634. valid: true,
  635. desc: "valid",
  636. },
  637. { // case[2]
  638. portRange: "90-1",
  639. valid: true,
  640. desc: "ipset util can accept the input of begin port number can be less than end port number",
  641. },
  642. { // case[3]
  643. portRange: DefaultPortRange,
  644. valid: true,
  645. desc: "default port range is valid, of course",
  646. },
  647. { // case[4]
  648. portRange: "12",
  649. valid: false,
  650. desc: "a single number is invalid",
  651. },
  652. { // case[5]
  653. portRange: "1-",
  654. valid: false,
  655. desc: "should specify end port",
  656. },
  657. { // case[6]
  658. portRange: "-100",
  659. valid: false,
  660. desc: "should specify begin port",
  661. },
  662. { // case[7]
  663. portRange: "1:100",
  664. valid: false,
  665. desc: "delimiter should be -",
  666. },
  667. { // case[8]
  668. portRange: "1~100",
  669. valid: false,
  670. desc: "delimiter should be -",
  671. },
  672. { // case[9]
  673. portRange: "1,100",
  674. valid: false,
  675. desc: "delimiter should be -",
  676. },
  677. { // case[10]
  678. portRange: "100-100",
  679. valid: true,
  680. desc: "begin port number can be equal to end port number",
  681. },
  682. { // case[11]
  683. portRange: "",
  684. valid: false,
  685. desc: "empty string is invalid",
  686. },
  687. { // case[12]
  688. portRange: "-1-12",
  689. valid: false,
  690. desc: "port number can not be negative value",
  691. },
  692. { // case[13]
  693. portRange: "-1--8",
  694. valid: false,
  695. desc: "port number can not be negative value",
  696. },
  697. }
  698. for i := range testCases {
  699. valid := validatePortRange(testCases[i].portRange)
  700. if valid != testCases[i].valid {
  701. t.Errorf("case [%d]: unexpected mismatch, expect valid[%v], got valid[%v], desc: %s", i, testCases[i].valid, valid, testCases[i].desc)
  702. }
  703. }
  704. }
  705. func Test_validateFamily(t *testing.T) {
  706. testCases := []struct {
  707. family string
  708. valid bool
  709. }{
  710. { // case[0]
  711. family: "foo",
  712. valid: false,
  713. },
  714. { // case[1]
  715. family: ProtocolFamilyIPV4,
  716. valid: true,
  717. },
  718. { // case[2]
  719. family: ProtocolFamilyIPV6,
  720. valid: true,
  721. },
  722. { // case[3]
  723. family: "ipv4",
  724. valid: false,
  725. },
  726. { // case[4]
  727. family: "ipv6",
  728. valid: false,
  729. },
  730. { // case[5]
  731. family: "tcp",
  732. valid: false,
  733. },
  734. { // case[6]
  735. family: "udp",
  736. valid: false,
  737. },
  738. { // case[7]
  739. family: "",
  740. valid: false,
  741. },
  742. { // case[8]
  743. family: "sctp",
  744. valid: false,
  745. },
  746. }
  747. for i := range testCases {
  748. valid := validateHashFamily(testCases[i].family)
  749. if valid != testCases[i].valid {
  750. t.Errorf("case [%d]: unexpected mismatch, expect valid[%v], got valid[%v]", i, testCases[i].valid, valid)
  751. }
  752. }
  753. }
  754. func Test_validateProtocol(t *testing.T) {
  755. testCases := []struct {
  756. protocol string
  757. valid bool
  758. desc string
  759. }{
  760. { // case[0]
  761. protocol: "foo",
  762. valid: false,
  763. },
  764. { // case[1]
  765. protocol: ProtocolTCP,
  766. valid: true,
  767. },
  768. { // case[2]
  769. protocol: ProtocolUDP,
  770. valid: true,
  771. },
  772. { // case[3]
  773. protocol: "ipv4",
  774. valid: false,
  775. },
  776. { // case[4]
  777. protocol: "ipv6",
  778. valid: false,
  779. },
  780. { // case[5]
  781. protocol: "TCP",
  782. valid: false,
  783. desc: "should be low case",
  784. },
  785. { // case[6]
  786. protocol: "UDP",
  787. valid: false,
  788. desc: "should be low case",
  789. },
  790. { // case[7]
  791. protocol: "",
  792. valid: false,
  793. },
  794. { // case[8]
  795. protocol: ProtocolSCTP,
  796. valid: true,
  797. },
  798. }
  799. for i := range testCases {
  800. valid := validateProtocol(testCases[i].protocol)
  801. if valid != testCases[i].valid {
  802. t.Errorf("case [%d]: unexpected mismatch, expect valid[%v], got valid[%v], desc: %s", i, testCases[i].valid, valid, testCases[i].desc)
  803. }
  804. }
  805. }
  806. func TestValidateIPSet(t *testing.T) {
  807. testCases := []struct {
  808. ipset *IPSet
  809. valid bool
  810. desc string
  811. }{
  812. { // case[0]
  813. ipset: &IPSet{
  814. Name: "test",
  815. SetType: HashIPPort,
  816. HashFamily: ProtocolFamilyIPV4,
  817. HashSize: 1024,
  818. MaxElem: 1024,
  819. },
  820. valid: true,
  821. },
  822. { // case[1]
  823. ipset: &IPSet{
  824. Name: "SET",
  825. SetType: BitmapPort,
  826. HashFamily: ProtocolFamilyIPV6,
  827. HashSize: 65535,
  828. MaxElem: 2048,
  829. PortRange: DefaultPortRange,
  830. },
  831. valid: true,
  832. },
  833. { // case[2]
  834. ipset: &IPSet{
  835. Name: "foo",
  836. SetType: BitmapPort,
  837. HashFamily: ProtocolFamilyIPV6,
  838. HashSize: 65535,
  839. MaxElem: 2048,
  840. },
  841. valid: false,
  842. desc: "should specify right port range for bitmap type set",
  843. },
  844. { // case[3]
  845. ipset: &IPSet{
  846. Name: "bar",
  847. SetType: BitmapPort,
  848. HashFamily: ProtocolFamilyIPV6,
  849. HashSize: 0,
  850. MaxElem: 2048,
  851. },
  852. valid: false,
  853. desc: "wrong hash size number",
  854. },
  855. { // case[4]
  856. ipset: &IPSet{
  857. Name: "baz",
  858. SetType: BitmapPort,
  859. HashFamily: ProtocolFamilyIPV6,
  860. HashSize: 1024,
  861. MaxElem: -1,
  862. },
  863. valid: false,
  864. desc: "wrong hash max elem number",
  865. },
  866. { // case[5]
  867. ipset: &IPSet{
  868. Name: "baz",
  869. SetType: HashIPPortNet,
  870. HashFamily: "ip",
  871. HashSize: 1024,
  872. MaxElem: 1024,
  873. },
  874. valid: false,
  875. desc: "wrong protocol",
  876. },
  877. { // case[6]
  878. ipset: &IPSet{
  879. Name: "foo-bar",
  880. SetType: "xxx",
  881. HashFamily: ProtocolFamilyIPV4,
  882. HashSize: 1024,
  883. MaxElem: 1024,
  884. },
  885. valid: false,
  886. desc: "wrong set type",
  887. },
  888. }
  889. for i := range testCases {
  890. valid := testCases[i].ipset.Validate()
  891. if valid != testCases[i].valid {
  892. t.Errorf("case [%d]: unexpected mismatch, expect valid[%v], got valid[%v], desc: %s", i, testCases[i].valid, valid, testCases[i].desc)
  893. }
  894. }
  895. }
  896. func Test_setIPSetDefaults(t *testing.T) {
  897. testCases := []struct {
  898. name string
  899. set *IPSet
  900. expect *IPSet
  901. }{
  902. {
  903. name: "test all the IPSet fields not present",
  904. set: &IPSet{
  905. Name: "test1",
  906. },
  907. expect: &IPSet{
  908. Name: "test1",
  909. SetType: HashIPPort,
  910. HashFamily: ProtocolFamilyIPV4,
  911. HashSize: 1024,
  912. MaxElem: 65536,
  913. PortRange: DefaultPortRange,
  914. },
  915. },
  916. {
  917. name: "test all the IPSet fields present",
  918. set: &IPSet{
  919. Name: "test2",
  920. SetType: BitmapPort,
  921. HashFamily: ProtocolFamilyIPV6,
  922. HashSize: 65535,
  923. MaxElem: 2048,
  924. PortRange: DefaultPortRange,
  925. },
  926. expect: &IPSet{
  927. Name: "test2",
  928. SetType: BitmapPort,
  929. HashFamily: ProtocolFamilyIPV6,
  930. HashSize: 65535,
  931. MaxElem: 2048,
  932. PortRange: DefaultPortRange,
  933. },
  934. },
  935. {
  936. name: "test part of the IPSet fields present",
  937. set: &IPSet{
  938. Name: "test3",
  939. SetType: BitmapPort,
  940. HashFamily: ProtocolFamilyIPV6,
  941. HashSize: 65535,
  942. },
  943. expect: &IPSet{
  944. Name: "test3",
  945. SetType: BitmapPort,
  946. HashFamily: ProtocolFamilyIPV6,
  947. HashSize: 65535,
  948. MaxElem: 65536,
  949. PortRange: DefaultPortRange,
  950. },
  951. },
  952. }
  953. for _, test := range testCases {
  954. t.Run(test.name, func(t *testing.T) {
  955. test.set.setIPSetDefaults()
  956. if !reflect.DeepEqual(test.set, test.expect) {
  957. t.Errorf("expected ipset struct: %v, got ipset struct: %v", test.expect, test.set)
  958. }
  959. })
  960. }
  961. }
  962. func Test_checkIPandProtocol(t *testing.T) {
  963. testset := &IPSet{
  964. Name: "test1",
  965. SetType: HashIPPort,
  966. HashFamily: ProtocolFamilyIPV4,
  967. HashSize: 1024,
  968. MaxElem: 65536,
  969. PortRange: DefaultPortRange,
  970. }
  971. testCases := []struct {
  972. name string
  973. entry *Entry
  974. valid bool
  975. }{
  976. {
  977. name: "valid IP with ProtocolTCP",
  978. entry: &Entry{
  979. SetType: HashIPPort,
  980. IP: "1.2.3.4",
  981. Protocol: ProtocolTCP,
  982. Port: 8080,
  983. },
  984. valid: true,
  985. },
  986. {
  987. name: "valid IP with ProtocolUDP",
  988. entry: &Entry{
  989. SetType: HashIPPort,
  990. IP: "1.2.3.4",
  991. Protocol: ProtocolUDP,
  992. Port: 8080,
  993. },
  994. valid: true,
  995. },
  996. {
  997. name: "valid IP with nil Protocol",
  998. entry: &Entry{
  999. SetType: HashIPPort,
  1000. IP: "1.2.3.4",
  1001. Port: 8080,
  1002. },
  1003. valid: true,
  1004. },
  1005. {
  1006. name: "valid IP with invalid Protocol",
  1007. entry: &Entry{
  1008. SetType: HashIPPort,
  1009. IP: "1.2.3.4",
  1010. Protocol: "invalidProtocol",
  1011. Port: 8080,
  1012. },
  1013. valid: false,
  1014. },
  1015. {
  1016. name: "invalid IP with ProtocolTCP",
  1017. entry: &Entry{
  1018. SetType: HashIPPort,
  1019. IP: "1.2.3.423",
  1020. Protocol: ProtocolTCP,
  1021. Port: 8080,
  1022. },
  1023. valid: false,
  1024. },
  1025. }
  1026. for _, test := range testCases {
  1027. t.Run(test.name, func(t *testing.T) {
  1028. result := test.entry.checkIPandProtocol(testset)
  1029. if result != test.valid {
  1030. t.Errorf("expected valid: %v, got valid: %v", test.valid, result)
  1031. }
  1032. })
  1033. }
  1034. }
  1035. func Test_parsePortRange(t *testing.T) {
  1036. testCases := []struct {
  1037. portRange string
  1038. expectErr bool
  1039. beginPort int
  1040. endPort int
  1041. desc string
  1042. }{
  1043. { // case[0]
  1044. portRange: "1-100",
  1045. expectErr: false,
  1046. beginPort: 1,
  1047. endPort: 100,
  1048. },
  1049. { // case[1]
  1050. portRange: "0-0",
  1051. expectErr: false,
  1052. beginPort: 0,
  1053. endPort: 0,
  1054. },
  1055. { // case[2]
  1056. portRange: "100-10",
  1057. expectErr: false,
  1058. beginPort: 10,
  1059. endPort: 100,
  1060. },
  1061. { // case[3]
  1062. portRange: "1024",
  1063. expectErr: true,
  1064. desc: "single port number is not allowed",
  1065. },
  1066. { // case[4]
  1067. portRange: DefaultPortRange,
  1068. expectErr: false,
  1069. beginPort: 0,
  1070. endPort: 65535,
  1071. },
  1072. { // case[5]
  1073. portRange: "1-",
  1074. expectErr: true,
  1075. desc: "should specify end port",
  1076. },
  1077. { // case[6]
  1078. portRange: "-100",
  1079. expectErr: true,
  1080. desc: "should specify begin port",
  1081. },
  1082. { // case[7]
  1083. portRange: "1:100",
  1084. expectErr: true,
  1085. desc: "delimiter should be -",
  1086. },
  1087. { // case[8]
  1088. portRange: "1~100",
  1089. expectErr: true,
  1090. desc: "delimiter should be -",
  1091. },
  1092. { // case[9]
  1093. portRange: "1,100",
  1094. expectErr: true,
  1095. desc: "delimiter should be -",
  1096. },
  1097. { // case[10]
  1098. portRange: "100-100",
  1099. expectErr: false,
  1100. desc: "begin port number can be equal to end port number",
  1101. beginPort: 100,
  1102. endPort: 100,
  1103. },
  1104. { // case[11]
  1105. portRange: "",
  1106. expectErr: false,
  1107. desc: "empty string indicates default port range",
  1108. beginPort: 0,
  1109. endPort: 65535,
  1110. },
  1111. { // case[12]
  1112. portRange: "-1-12",
  1113. expectErr: true,
  1114. desc: "port number can not be negative value",
  1115. },
  1116. { // case[13]
  1117. portRange: "-1--8",
  1118. expectErr: true,
  1119. desc: "port number can not be negative value",
  1120. },
  1121. }
  1122. for i := range testCases {
  1123. begin, end, err := parsePortRange(testCases[i].portRange)
  1124. if err != nil {
  1125. if !testCases[i].expectErr {
  1126. t.Errorf("case [%d]: unexpected err: %v, desc: %s", i, err, testCases[i].desc)
  1127. }
  1128. continue
  1129. }
  1130. if begin != testCases[i].beginPort || end != testCases[i].endPort {
  1131. t.Errorf("case [%d]: unexpected mismatch [beginPort, endPort] pair, expect [%d, %d], got [%d, %d], desc: %s", i, testCases[i].beginPort, testCases[i].endPort, begin, end, testCases[i].desc)
  1132. }
  1133. }
  1134. }
  1135. // This is a coarse test, but it offers some modicum of confidence as the code is evolved.
  1136. func TestValidateEntry(t *testing.T) {
  1137. testCases := []struct {
  1138. entry *Entry
  1139. set *IPSet
  1140. valid bool
  1141. desc string
  1142. }{
  1143. { // case[0]
  1144. entry: &Entry{
  1145. SetType: BitmapPort,
  1146. },
  1147. set: &IPSet{
  1148. PortRange: DefaultPortRange,
  1149. },
  1150. valid: true,
  1151. desc: "port number can be empty, default is 0. And port number is in the range of its ipset's port range",
  1152. },
  1153. { // case[1]
  1154. entry: &Entry{
  1155. SetType: BitmapPort,
  1156. Port: 0,
  1157. },
  1158. set: &IPSet{
  1159. PortRange: DefaultPortRange,
  1160. },
  1161. valid: true,
  1162. desc: "port number can be 0. And port number is in the range of its ipset's port range",
  1163. },
  1164. { // case[2]
  1165. entry: &Entry{
  1166. SetType: BitmapPort,
  1167. Port: -1,
  1168. },
  1169. valid: false,
  1170. desc: "port number can not be negative value",
  1171. },
  1172. { // case[3]
  1173. entry: &Entry{
  1174. SetType: BitmapPort,
  1175. Port: 1080,
  1176. },
  1177. set: &IPSet{
  1178. Name: "baz",
  1179. PortRange: DefaultPortRange,
  1180. },
  1181. desc: "port number is in the range of its ipset's port range",
  1182. valid: true,
  1183. },
  1184. { // case[4]
  1185. entry: &Entry{
  1186. SetType: BitmapPort,
  1187. Port: 1080,
  1188. },
  1189. set: &IPSet{
  1190. Name: "foo",
  1191. PortRange: "0-1079",
  1192. },
  1193. desc: "port number is NOT in the range of its ipset's port range",
  1194. valid: false,
  1195. },
  1196. { // case[5]
  1197. entry: &Entry{
  1198. SetType: HashIPPort,
  1199. IP: "1.2.3.4",
  1200. Protocol: ProtocolTCP,
  1201. Port: 8080,
  1202. },
  1203. set: &IPSet{
  1204. Name: "bar",
  1205. },
  1206. valid: true,
  1207. },
  1208. { // case[6]
  1209. entry: &Entry{
  1210. SetType: HashIPPort,
  1211. IP: "1.2.3.4",
  1212. Protocol: ProtocolUDP,
  1213. Port: 0,
  1214. },
  1215. set: &IPSet{
  1216. Name: "bar",
  1217. },
  1218. valid: true,
  1219. },
  1220. { // case[7]
  1221. entry: &Entry{
  1222. SetType: HashIPPort,
  1223. IP: "FE80:0000:0000:0000:0202:B3FF:FE1E:8329",
  1224. Protocol: ProtocolTCP,
  1225. Port: 1111,
  1226. },
  1227. set: &IPSet{
  1228. Name: "ipv6",
  1229. },
  1230. valid: true,
  1231. },
  1232. { // case[8]
  1233. entry: &Entry{
  1234. SetType: HashIPPort,
  1235. IP: "",
  1236. Protocol: ProtocolTCP,
  1237. Port: 1234,
  1238. },
  1239. set: &IPSet{
  1240. Name: "empty-ip",
  1241. },
  1242. valid: false,
  1243. },
  1244. { // case[9]
  1245. entry: &Entry{
  1246. SetType: HashIPPort,
  1247. IP: "1-2-3-4",
  1248. Protocol: ProtocolTCP,
  1249. Port: 8900,
  1250. },
  1251. set: &IPSet{
  1252. Name: "bad-ip",
  1253. },
  1254. valid: false,
  1255. },
  1256. { // case[10]
  1257. entry: &Entry{
  1258. SetType: HashIPPort,
  1259. IP: "10.20.30.40",
  1260. Protocol: "",
  1261. Port: 8090,
  1262. },
  1263. set: &IPSet{
  1264. Name: "empty-protocol",
  1265. },
  1266. valid: true,
  1267. },
  1268. { // case[11]
  1269. entry: &Entry{
  1270. SetType: HashIPPort,
  1271. IP: "10.20.30.40",
  1272. Protocol: "ICMP",
  1273. Port: 8090,
  1274. },
  1275. set: &IPSet{
  1276. Name: "unsupported-protocol",
  1277. },
  1278. valid: false,
  1279. },
  1280. { // case[11]
  1281. entry: &Entry{
  1282. SetType: HashIPPort,
  1283. IP: "10.20.30.40",
  1284. Protocol: "ICMP",
  1285. Port: -1,
  1286. },
  1287. set: &IPSet{
  1288. // TODO: set name string with white space?
  1289. Name: "negative-port-number",
  1290. },
  1291. valid: false,
  1292. },
  1293. { // case[12]
  1294. entry: &Entry{
  1295. SetType: HashIPPortIP,
  1296. IP: "10.20.30.40",
  1297. Protocol: ProtocolUDP,
  1298. Port: 53,
  1299. IP2: "10.20.30.40",
  1300. },
  1301. set: &IPSet{
  1302. Name: "LOOP-BACK",
  1303. },
  1304. valid: true,
  1305. },
  1306. { // case[13]
  1307. entry: &Entry{
  1308. SetType: HashIPPortIP,
  1309. IP: "10.20.30.40",
  1310. Protocol: ProtocolUDP,
  1311. Port: 53,
  1312. IP2: "",
  1313. },
  1314. set: &IPSet{
  1315. Name: "empty IP2",
  1316. },
  1317. valid: false,
  1318. },
  1319. { // case[14]
  1320. entry: &Entry{
  1321. SetType: HashIPPortIP,
  1322. IP: "10.20.30.40",
  1323. Protocol: ProtocolUDP,
  1324. Port: 53,
  1325. IP2: "foo",
  1326. },
  1327. set: &IPSet{
  1328. Name: "invalid IP2",
  1329. },
  1330. valid: false,
  1331. },
  1332. { // case[15]
  1333. entry: &Entry{
  1334. SetType: HashIPPortIP,
  1335. IP: "10.20.30.40",
  1336. Protocol: ProtocolTCP,
  1337. Port: 0,
  1338. IP2: "1.2.3.4",
  1339. },
  1340. set: &IPSet{
  1341. Name: "zero port",
  1342. },
  1343. valid: true,
  1344. },
  1345. { // case[16]
  1346. entry: &Entry{
  1347. SetType: HashIPPortIP,
  1348. IP: "10::40",
  1349. Protocol: ProtocolTCP,
  1350. Port: 10000,
  1351. IP2: "1::4",
  1352. },
  1353. set: &IPSet{
  1354. Name: "IPV6",
  1355. // TODO: check set's hash family
  1356. },
  1357. valid: true,
  1358. },
  1359. { // case[17]
  1360. entry: &Entry{
  1361. SetType: HashIPPortIP,
  1362. IP: "",
  1363. Protocol: ProtocolTCP,
  1364. Port: 1234,
  1365. IP2: "1.2.3.4",
  1366. },
  1367. set: &IPSet{
  1368. Name: "empty-ip",
  1369. },
  1370. valid: false,
  1371. },
  1372. { // case[18]
  1373. entry: &Entry{
  1374. SetType: HashIPPortIP,
  1375. IP: "1-2-3-4",
  1376. Protocol: ProtocolTCP,
  1377. Port: 8900,
  1378. IP2: "10.20.30.41",
  1379. },
  1380. set: &IPSet{
  1381. Name: "bad-ip",
  1382. },
  1383. valid: false,
  1384. },
  1385. { // case[19]
  1386. entry: &Entry{
  1387. SetType: HashIPPortIP,
  1388. IP: "10.20.30.40",
  1389. Protocol: ProtocolSCTP,
  1390. Port: 8090,
  1391. IP2: "10.20.30.41",
  1392. },
  1393. set: &IPSet{
  1394. Name: "sctp",
  1395. },
  1396. valid: true,
  1397. },
  1398. { // case[20]
  1399. entry: &Entry{
  1400. SetType: HashIPPortIP,
  1401. IP: "10.20.30.40",
  1402. Protocol: "ICMP",
  1403. Port: -1,
  1404. IP2: "100.200.30.41",
  1405. },
  1406. set: &IPSet{
  1407. Name: "negative-port-number",
  1408. },
  1409. valid: false,
  1410. },
  1411. { // case[21]
  1412. entry: &Entry{
  1413. SetType: HashIPPortNet,
  1414. IP: "10.20.30.40",
  1415. Protocol: ProtocolTCP,
  1416. Port: 53,
  1417. // TODO: CIDR /32 may not be valid
  1418. Net: "10.20.30.0/24",
  1419. },
  1420. set: &IPSet{
  1421. Name: "abc",
  1422. },
  1423. valid: true,
  1424. },
  1425. { // case[22]
  1426. entry: &Entry{
  1427. SetType: HashIPPortNet,
  1428. IP: "11.21.31.41",
  1429. Protocol: ProtocolUDP,
  1430. Port: 1122,
  1431. Net: "",
  1432. },
  1433. set: &IPSet{
  1434. Name: "empty Net",
  1435. },
  1436. valid: false,
  1437. },
  1438. { // case[23]
  1439. entry: &Entry{
  1440. SetType: HashIPPortNet,
  1441. IP: "10.20.30.40",
  1442. Protocol: ProtocolUDP,
  1443. Port: 8080,
  1444. Net: "x-y-z-w",
  1445. },
  1446. set: &IPSet{
  1447. Name: "invalid Net",
  1448. },
  1449. valid: false,
  1450. },
  1451. { // case[24]
  1452. entry: &Entry{
  1453. SetType: HashIPPortNet,
  1454. IP: "10.20.30.40",
  1455. Protocol: ProtocolTCP,
  1456. Port: 0,
  1457. Net: "10.1.0.0/16",
  1458. },
  1459. set: &IPSet{
  1460. Name: "zero port",
  1461. },
  1462. valid: true,
  1463. },
  1464. { // case[25]
  1465. entry: &Entry{
  1466. SetType: HashIPPortNet,
  1467. IP: "10::40",
  1468. Protocol: ProtocolTCP,
  1469. Port: 80,
  1470. Net: "2001:db8::/32",
  1471. },
  1472. set: &IPSet{
  1473. Name: "IPV6",
  1474. // TODO: check set's hash family
  1475. },
  1476. valid: true,
  1477. },
  1478. { // case[26]
  1479. entry: &Entry{
  1480. SetType: HashIPPortNet,
  1481. IP: "",
  1482. Protocol: ProtocolTCP,
  1483. Port: 1234,
  1484. Net: "1.2.3.4/22",
  1485. },
  1486. set: &IPSet{
  1487. Name: "empty-ip",
  1488. },
  1489. valid: false,
  1490. },
  1491. { // case[27]
  1492. entry: &Entry{
  1493. SetType: HashIPPortNet,
  1494. IP: "1-2-3-4",
  1495. Protocol: ProtocolTCP,
  1496. Port: 8900,
  1497. Net: "10.20.30.41/31",
  1498. },
  1499. set: &IPSet{
  1500. Name: "bad-ip",
  1501. },
  1502. valid: false,
  1503. },
  1504. { // case[28]
  1505. entry: &Entry{
  1506. SetType: HashIPPortIP,
  1507. IP: "10.20.30.40",
  1508. Protocol: "FOO",
  1509. Port: 8090,
  1510. IP2: "10.20.30.0/10",
  1511. },
  1512. set: &IPSet{
  1513. Name: "unsupported-protocol",
  1514. },
  1515. valid: false,
  1516. },
  1517. { // case[29]
  1518. entry: &Entry{
  1519. SetType: HashIPPortIP,
  1520. IP: "10.20.30.40",
  1521. Protocol: ProtocolUDP,
  1522. Port: -1,
  1523. IP2: "100.200.30.0/12",
  1524. },
  1525. set: &IPSet{
  1526. Name: "negative-port-number",
  1527. },
  1528. valid: false,
  1529. },
  1530. }
  1531. for i := range testCases {
  1532. valid := testCases[i].entry.Validate(testCases[i].set)
  1533. if valid != testCases[i].valid {
  1534. t.Errorf("case [%d]: unexpected mismatch, expect valid[%v], got valid[%v], desc: %s", i, testCases[i].valid, valid, testCases[i].entry)
  1535. }
  1536. }
  1537. }
  1538. func TestEntryString(t *testing.T) {
  1539. testCases := []struct {
  1540. name string
  1541. entry *Entry
  1542. expect string
  1543. }{
  1544. {
  1545. name: "test when SetType is HashIPPort",
  1546. entry: &Entry{
  1547. SetType: HashIPPort,
  1548. IP: "1.2.3.4",
  1549. Protocol: ProtocolTCP,
  1550. Port: 8080,
  1551. },
  1552. expect: "1.2.3.4,tcp:8080",
  1553. },
  1554. {
  1555. name: "test when SetType is HashIPPortIP",
  1556. entry: &Entry{
  1557. SetType: HashIPPortIP,
  1558. IP: "1.2.3.8",
  1559. Protocol: ProtocolUDP,
  1560. Port: 8081,
  1561. IP2: "1.2.3.8",
  1562. },
  1563. expect: "1.2.3.8,udp:8081,1.2.3.8",
  1564. },
  1565. {
  1566. name: "test when SetType is HashIPPortNet",
  1567. entry: &Entry{
  1568. SetType: HashIPPortNet,
  1569. IP: "192.168.1.2",
  1570. Protocol: ProtocolUDP,
  1571. Port: 80,
  1572. Net: "10.0.1.0/24",
  1573. },
  1574. expect: "192.168.1.2,udp:80,10.0.1.0/24",
  1575. },
  1576. {
  1577. name: "test when SetType is BitmapPort",
  1578. entry: &Entry{
  1579. SetType: BitmapPort,
  1580. Port: 80,
  1581. },
  1582. expect: "80",
  1583. },
  1584. {
  1585. name: "test when SetType is unknown",
  1586. entry: &Entry{
  1587. SetType: "unknown",
  1588. IP: "192.168.1.2",
  1589. Protocol: ProtocolUDP,
  1590. Port: 80,
  1591. Net: "10.0.1.0/24",
  1592. },
  1593. expect: "",
  1594. },
  1595. }
  1596. for _, test := range testCases {
  1597. t.Run(test.name, func(t *testing.T) {
  1598. result := test.entry.String()
  1599. if result != test.expect {
  1600. t.Errorf("Unexpected mismatch, expected: %s, got: %s", test.expect, result)
  1601. }
  1602. })
  1603. }
  1604. }