@@ -15,6 +15,7 @@ type mockIPTables struct {
1515 rules map [string ][]string
1616 methodErrors map [string ]error
1717 appendFunc func (table , chain string , rulespec ... string ) error
18+ insertFunc func (table , chain string , pos int , rulespec ... string ) error
1819}
1920
2021func newMockIPTables () * mockIPTables {
@@ -79,6 +80,9 @@ func (m *mockIPTables) Append(table, chain string, rulespec ...string) error {
7980}
8081
8182func (m * mockIPTables ) Insert (table , chain string , pos int , rulespec ... string ) error {
83+ if m .insertFunc != nil {
84+ return m .insertFunc (table , chain , pos , rulespec ... )
85+ }
8286 if err := m .methodErrors ["Insert" ]; err != nil {
8387 return err
8488 }
@@ -1362,3 +1366,177 @@ func TestClearAndDeleteChain(t *testing.T) {
13621366 })
13631367 }
13641368}
1369+
1370+ func TestCreateContainerChainDryRun (t * testing.T ) {
1371+ testCases := []struct {
1372+ name string
1373+ dryRun bool
1374+ defaultAction string
1375+ mockSetup func (* mockIPTables )
1376+ expectedRules []string
1377+ expectError bool
1378+ errorString string
1379+ }{
1380+ {
1381+ name : "Dry run mode - successful creation" ,
1382+ dryRun : true ,
1383+ defaultAction : "DROP" ,
1384+ mockSetup : nil ,
1385+ expectedRules : []string {
1386+ "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" ,
1387+ "-j LOG --log-prefix [CNI-OUTBOUND-DEFAULT-DROP]" ,
1388+ "-j ACCEPT" ,
1389+ },
1390+ expectError : false ,
1391+ },
1392+ {
1393+ name : "Dry run mode - logging rule append failure" ,
1394+ dryRun : true ,
1395+ defaultAction : "DROP" ,
1396+ mockSetup : func (m * mockIPTables ) {
1397+ callCount := 0
1398+ m .appendFunc = func (table , chain string , rulespec ... string ) error {
1399+ callCount ++
1400+ if callCount == 2 && strings .Contains (strings .Join (rulespec , " " ), "-j LOG" ) {
1401+ return fmt .Errorf ("mock logging rule error" )
1402+ }
1403+ rule := strings .Join (rulespec , " " )
1404+ if m .rules [chain ] == nil {
1405+ m .rules [chain ] = []string {}
1406+ }
1407+ m .rules [chain ] = append (m .rules [chain ], rule )
1408+ return nil
1409+ }
1410+ },
1411+ expectError : true ,
1412+ errorString : "failed to add default action logging rule: mock logging rule error" ,
1413+ },
1414+ {
1415+ name : "Normal mode - successful creation" ,
1416+ dryRun : false ,
1417+ defaultAction : "DROP" ,
1418+ mockSetup : nil ,
1419+ expectedRules : []string {
1420+ "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" ,
1421+ "-j DROP" ,
1422+ },
1423+ expectError : false ,
1424+ },
1425+ }
1426+
1427+ for _ , tc := range testCases {
1428+ t .Run (tc .name , func (t * testing.T ) {
1429+ mockIpt := newMockIPTables ()
1430+ if tc .mockSetup != nil {
1431+ tc .mockSetup (mockIpt )
1432+ }
1433+
1434+ manager := & IPTablesManager {
1435+ ipt : mockIpt ,
1436+ mainChainName : "CNI-OUTBOUND" ,
1437+ defaultAction : tc .defaultAction ,
1438+ dryRun : tc .dryRun ,
1439+ }
1440+
1441+ err := manager .CreateContainerChain ("TEST-CHAIN" )
1442+
1443+ if tc .expectError {
1444+ assert .Error (t , err )
1445+ if tc .errorString != "" {
1446+ assert .Equal (t , tc .errorString , err .Error ())
1447+ }
1448+ return
1449+ }
1450+
1451+ assert .NoError (t , err )
1452+ assert .True (t , mockIpt .chains ["TEST-CHAIN" ])
1453+
1454+ rules := mockIpt .rules ["TEST-CHAIN" ]
1455+ assert .Equal (t , len (tc .expectedRules ), len (rules ), "Expected %d rules, got %d" , len (tc .expectedRules ), len (rules ))
1456+
1457+ for i , expectedRule := range tc .expectedRules {
1458+ assert .Contains (t , rules [i ], expectedRule , "Rule %d doesn't match expected" , i )
1459+ }
1460+ })
1461+ }
1462+ }
1463+
1464+ func TestAddRuleLoggingError (t * testing.T ) {
1465+ testCases := []struct {
1466+ name string
1467+ rule OutboundRule
1468+ mockSetup func (* mockIPTables )
1469+ expectedError string
1470+ }{
1471+ {
1472+ name : "Dry run mode - logging rule insertion failure" ,
1473+ rule : OutboundRule {
1474+ Host : "192.168.1.1" ,
1475+ Proto : "tcp" ,
1476+ Port : "80" ,
1477+ Action : "DROP" ,
1478+ },
1479+ mockSetup : func (m * mockIPTables ) {
1480+ // Mock Insert to fail on logging rule
1481+ m .methodErrors ["Insert" ] = fmt .Errorf ("mock logging rule insertion error" )
1482+ },
1483+ expectedError : "failed to add logging rule: mock logging rule insertion error" ,
1484+ },
1485+ {
1486+ name : "Dry run mode - logging rule insertion success but action rule failure" ,
1487+ rule : OutboundRule {
1488+ Host : "192.168.1.1" ,
1489+ Proto : "tcp" ,
1490+ Port : "80" ,
1491+ Action : "DROP" ,
1492+ },
1493+ mockSetup : func (m * mockIPTables ) {
1494+ callCount := 0
1495+ m .insertFunc = func (table , chain string , pos int , rulespec ... string ) error {
1496+ callCount ++
1497+ if callCount == 1 {
1498+ // Let the logging rule succeed
1499+ rule := strings .Join (rulespec , " " )
1500+ if m .rules [chain ] == nil {
1501+ m .rules [chain ] = []string {}
1502+ }
1503+ m .rules [chain ] = append (m .rules [chain ], rule )
1504+ return nil
1505+ }
1506+ // Make the action rule fail
1507+ return fmt .Errorf ("mock action rule error" )
1508+ }
1509+ },
1510+ expectedError : "mock action rule error" ,
1511+ },
1512+ }
1513+
1514+ for _ , tc := range testCases {
1515+ t .Run (tc .name , func (t * testing.T ) {
1516+ mockIpt := newMockIPTables ()
1517+ if tc .mockSetup != nil {
1518+ tc .mockSetup (mockIpt )
1519+ }
1520+
1521+ manager := & IPTablesManager {
1522+ ipt : mockIpt ,
1523+ mainChainName : "CNI-OUTBOUND" ,
1524+ defaultAction : "DROP" ,
1525+ dryRun : true ,
1526+ }
1527+
1528+ err := manager .AddRule ("TEST-CHAIN" , tc .rule )
1529+
1530+ assert .Error (t , err )
1531+ assert .Equal (t , tc .expectedError , err .Error ())
1532+
1533+ // For the second test case, verify the logging rule was added before the error
1534+ if strings .Contains (tc .name , "success but action rule failure" ) {
1535+ rules := mockIpt .rules ["TEST-CHAIN" ]
1536+ assert .Equal (t , 1 , len (rules ))
1537+ assert .Contains (t , rules [0 ], "-j LOG" )
1538+ assert .Contains (t , rules [0 ], "[CNI-OUTBOUND-BLOCKED]" )
1539+ }
1540+ })
1541+ }
1542+ }
0 commit comments