2023-04-17 11:15:37 +02:00
//go:build !android
2022-09-05 09:06:35 +02:00
package routemanager
import (
"context"
2023-04-17 11:15:37 +02:00
"testing"
2022-09-05 09:06:35 +02:00
"github.com/coreos/go-iptables/iptables"
"github.com/stretchr/testify/require"
)
func TestIptablesManager_RestoreOrCreateContainers ( t * testing . T ) {
if ! isIptablesSupported ( ) {
t . SkipNow ( )
}
ctx , cancel := context . WithCancel ( context . TODO ( ) )
ipv4Client , _ := iptables . NewWithProtocol ( iptables . ProtocolIPv4 )
ipv6Client , _ := iptables . NewWithProtocol ( iptables . ProtocolIPv6 )
manager := & iptablesManager {
ctx : ctx ,
stop : cancel ,
ipv4Client : ipv4Client ,
ipv6Client : ipv6Client ,
rules : make ( map [ string ] map [ string ] [ ] string ) ,
}
defer manager . CleanRoutingRules ( )
err := manager . RestoreOrCreateContainers ( )
require . NoError ( t , err , "shouldn't return error" )
require . Len ( t , manager . rules , 2 , "should have created maps for ipv4 and ipv6" )
require . Len ( t , manager . rules [ ipv4 ] , 2 , "should have created minimal rules for ipv4" )
exists , err := ipv4Client . Exists ( iptablesFilterTable , iptablesForwardChain , manager . rules [ ipv4 ] [ ipv4Forwarding ] ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , ipv4 , iptablesFilterTable , iptablesForwardChain )
require . True ( t , exists , "forwarding rule should exist" )
exists , err = ipv4Client . Exists ( iptablesNatTable , iptablesPostRoutingChain , manager . rules [ ipv4 ] [ ipv4Nat ] ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , ipv4 , iptablesNatTable , iptablesPostRoutingChain )
require . True ( t , exists , "postrouting rule should exist" )
require . Len ( t , manager . rules [ ipv6 ] , 2 , "should have created minimal rules for ipv6" )
exists , err = ipv6Client . Exists ( iptablesFilterTable , iptablesForwardChain , manager . rules [ ipv6 ] [ ipv6Forwarding ] ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , ipv6 , iptablesFilterTable , iptablesForwardChain )
require . True ( t , exists , "forwarding rule should exist" )
exists , err = ipv6Client . Exists ( iptablesNatTable , iptablesPostRoutingChain , manager . rules [ ipv6 ] [ ipv6Nat ] ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , ipv6 , iptablesNatTable , iptablesPostRoutingChain )
require . True ( t , exists , "postrouting rule should exist" )
pair := routerPair {
ID : "abc" ,
source : "100.100.100.1/32" ,
destination : "100.100.100.0/24" ,
masquerade : true ,
}
forward4RuleKey := genKey ( forwardingFormat , pair . ID )
forward4Rule := genRuleSpec ( routingFinalForwardJump , forward4RuleKey , pair . source , pair . destination )
err = ipv4Client . Insert ( iptablesFilterTable , iptablesRoutingForwardingChain , 1 , forward4Rule ... )
require . NoError ( t , err , "inserting rule should not return error" )
nat4RuleKey := genKey ( natFormat , pair . ID )
nat4Rule := genRuleSpec ( routingFinalNatJump , nat4RuleKey , pair . source , pair . destination )
err = ipv4Client . Insert ( iptablesNatTable , iptablesRoutingNatChain , 1 , nat4Rule ... )
require . NoError ( t , err , "inserting rule should not return error" )
pair = routerPair {
ID : "abc" ,
source : "fc00::1/128" ,
destination : "fc11::/64" ,
masquerade : true ,
}
forward6RuleKey := genKey ( forwardingFormat , pair . ID )
forward6Rule := genRuleSpec ( routingFinalForwardJump , forward6RuleKey , pair . source , pair . destination )
err = ipv6Client . Insert ( iptablesFilterTable , iptablesRoutingForwardingChain , 1 , forward6Rule ... )
require . NoError ( t , err , "inserting rule should not return error" )
nat6RuleKey := genKey ( natFormat , pair . ID )
nat6Rule := genRuleSpec ( routingFinalNatJump , nat6RuleKey , pair . source , pair . destination )
err = ipv6Client . Insert ( iptablesNatTable , iptablesRoutingNatChain , 1 , nat6Rule ... )
require . NoError ( t , err , "inserting rule should not return error" )
delete ( manager . rules , ipv4 )
delete ( manager . rules , ipv6 )
err = manager . RestoreOrCreateContainers ( )
require . NoError ( t , err , "shouldn't return error" )
require . Len ( t , manager . rules [ ipv4 ] , 4 , "should have restored all rules for ipv4" )
foundRule , found := manager . rules [ ipv4 ] [ forward4RuleKey ]
require . True ( t , found , "forwarding rule should exist in the map" )
require . Equal ( t , forward4Rule [ : 4 ] , foundRule [ : 4 ] , "stored forwarding rule should match" )
foundRule , found = manager . rules [ ipv4 ] [ nat4RuleKey ]
require . True ( t , found , "nat rule should exist in the map" )
require . Equal ( t , nat4Rule [ : 4 ] , foundRule [ : 4 ] , "stored nat rule should match" )
require . Len ( t , manager . rules [ ipv6 ] , 4 , "should have restored all rules for ipv6" )
foundRule , found = manager . rules [ ipv6 ] [ forward6RuleKey ]
require . True ( t , found , "forwarding rule should exist in the map" )
require . Equal ( t , forward6Rule [ : 4 ] , foundRule [ : 4 ] , "stored forward rule should match" )
foundRule , found = manager . rules [ ipv6 ] [ nat6RuleKey ]
require . True ( t , found , "nat rule should exist in the map" )
require . Equal ( t , nat6Rule [ : 4 ] , foundRule [ : 4 ] , "stored nat rule should match" )
}
func TestIptablesManager_InsertRoutingRules ( t * testing . T ) {
if ! isIptablesSupported ( ) {
t . SkipNow ( )
}
for _ , testCase := range insertRuleTestCases {
t . Run ( testCase . name , func ( t * testing . T ) {
ctx , cancel := context . WithCancel ( context . TODO ( ) )
ipv4Client , _ := iptables . NewWithProtocol ( iptables . ProtocolIPv4 )
ipv6Client , _ := iptables . NewWithProtocol ( iptables . ProtocolIPv6 )
iptablesClient := ipv4Client
if testCase . ipVersion == ipv6 {
iptablesClient = ipv6Client
}
manager := & iptablesManager {
ctx : ctx ,
stop : cancel ,
ipv4Client : ipv4Client ,
ipv6Client : ipv6Client ,
rules : make ( map [ string ] map [ string ] [ ] string ) ,
}
defer manager . CleanRoutingRules ( )
err := manager . RestoreOrCreateContainers ( )
require . NoError ( t , err , "shouldn't return error" )
err = manager . InsertRoutingRules ( testCase . inputPair )
require . NoError ( t , err , "forwarding pair should be inserted" )
forwardRuleKey := genKey ( forwardingFormat , testCase . inputPair . ID )
forwardRule := genRuleSpec ( routingFinalForwardJump , forwardRuleKey , testCase . inputPair . source , testCase . inputPair . destination )
exists , err := iptablesClient . Exists ( iptablesFilterTable , iptablesRoutingForwardingChain , forwardRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesFilterTable , iptablesRoutingForwardingChain )
require . True ( t , exists , "forwarding rule should exist" )
foundRule , found := manager . rules [ testCase . ipVersion ] [ forwardRuleKey ]
require . True ( t , found , "forwarding rule should exist in the manager map" )
require . Equal ( t , forwardRule [ : 4 ] , foundRule [ : 4 ] , "stored forwarding rule should match" )
2022-09-30 11:39:15 +02:00
inForwardRuleKey := genKey ( inForwardingFormat , testCase . inputPair . ID )
inForwardRule := genRuleSpec ( routingFinalForwardJump , inForwardRuleKey , getInPair ( testCase . inputPair ) . source , getInPair ( testCase . inputPair ) . destination )
exists , err = iptablesClient . Exists ( iptablesFilterTable , iptablesRoutingForwardingChain , inForwardRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesFilterTable , iptablesRoutingForwardingChain )
require . True ( t , exists , "income forwarding rule should exist" )
foundRule , found = manager . rules [ testCase . ipVersion ] [ inForwardRuleKey ]
require . True ( t , found , "income forwarding rule should exist in the manager map" )
require . Equal ( t , inForwardRule [ : 4 ] , foundRule [ : 4 ] , "stored income forwarding rule should match" )
2022-09-05 09:06:35 +02:00
natRuleKey := genKey ( natFormat , testCase . inputPair . ID )
natRule := genRuleSpec ( routingFinalNatJump , natRuleKey , testCase . inputPair . source , testCase . inputPair . destination )
exists , err = iptablesClient . Exists ( iptablesNatTable , iptablesRoutingNatChain , natRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesNatTable , iptablesRoutingNatChain )
if testCase . inputPair . masquerade {
require . True ( t , exists , "nat rule should be created" )
foundNatRule , foundNat := manager . rules [ testCase . ipVersion ] [ natRuleKey ]
require . True ( t , foundNat , "nat rule should exist in the map" )
require . Equal ( t , natRule [ : 4 ] , foundNatRule [ : 4 ] , "stored nat rule should match" )
} else {
require . False ( t , exists , "nat rule should not be created" )
_ , foundNat := manager . rules [ testCase . ipVersion ] [ natRuleKey ]
2022-09-30 11:39:15 +02:00
require . False ( t , foundNat , "nat rule should not exist in the map" )
}
inNatRuleKey := genKey ( inNatFormat , testCase . inputPair . ID )
inNatRule := genRuleSpec ( routingFinalNatJump , inNatRuleKey , getInPair ( testCase . inputPair ) . source , getInPair ( testCase . inputPair ) . destination )
exists , err = iptablesClient . Exists ( iptablesNatTable , iptablesRoutingNatChain , inNatRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesNatTable , iptablesRoutingNatChain )
if testCase . inputPair . masquerade {
require . True ( t , exists , "income nat rule should be created" )
foundNatRule , foundNat := manager . rules [ testCase . ipVersion ] [ inNatRuleKey ]
require . True ( t , foundNat , "income nat rule should exist in the map" )
require . Equal ( t , inNatRule [ : 4 ] , foundNatRule [ : 4 ] , "stored income nat rule should match" )
} else {
require . False ( t , exists , "nat rule should not be created" )
_ , foundNat := manager . rules [ testCase . ipVersion ] [ inNatRuleKey ]
require . False ( t , foundNat , "income nat rule should not exist in the map" )
2022-09-05 09:06:35 +02:00
}
} )
}
}
func TestIptablesManager_RemoveRoutingRules ( t * testing . T ) {
if ! isIptablesSupported ( ) {
t . SkipNow ( )
}
for _ , testCase := range removeRuleTestCases {
t . Run ( testCase . name , func ( t * testing . T ) {
ctx , cancel := context . WithCancel ( context . TODO ( ) )
ipv4Client , _ := iptables . NewWithProtocol ( iptables . ProtocolIPv4 )
ipv6Client , _ := iptables . NewWithProtocol ( iptables . ProtocolIPv6 )
iptablesClient := ipv4Client
if testCase . ipVersion == ipv6 {
iptablesClient = ipv6Client
}
manager := & iptablesManager {
ctx : ctx ,
stop : cancel ,
ipv4Client : ipv4Client ,
ipv6Client : ipv6Client ,
rules : make ( map [ string ] map [ string ] [ ] string ) ,
}
defer manager . CleanRoutingRules ( )
err := manager . RestoreOrCreateContainers ( )
require . NoError ( t , err , "shouldn't return error" )
forwardRuleKey := genKey ( forwardingFormat , testCase . inputPair . ID )
forwardRule := genRuleSpec ( routingFinalForwardJump , forwardRuleKey , testCase . inputPair . source , testCase . inputPair . destination )
err = iptablesClient . Insert ( iptablesFilterTable , iptablesRoutingForwardingChain , 1 , forwardRule ... )
require . NoError ( t , err , "inserting rule should not return error" )
2022-09-30 11:39:15 +02:00
inForwardRuleKey := genKey ( inForwardingFormat , testCase . inputPair . ID )
inForwardRule := genRuleSpec ( routingFinalForwardJump , inForwardRuleKey , getInPair ( testCase . inputPair ) . source , getInPair ( testCase . inputPair ) . destination )
err = iptablesClient . Insert ( iptablesFilterTable , iptablesRoutingForwardingChain , 1 , inForwardRule ... )
require . NoError ( t , err , "inserting rule should not return error" )
2022-09-05 09:06:35 +02:00
natRuleKey := genKey ( natFormat , testCase . inputPair . ID )
natRule := genRuleSpec ( routingFinalNatJump , natRuleKey , testCase . inputPair . source , testCase . inputPair . destination )
err = iptablesClient . Insert ( iptablesNatTable , iptablesRoutingNatChain , 1 , natRule ... )
require . NoError ( t , err , "inserting rule should not return error" )
2022-09-30 11:39:15 +02:00
inNatRuleKey := genKey ( inNatFormat , testCase . inputPair . ID )
inNatRule := genRuleSpec ( routingFinalNatJump , inNatRuleKey , getInPair ( testCase . inputPair ) . source , getInPair ( testCase . inputPair ) . destination )
err = iptablesClient . Insert ( iptablesNatTable , iptablesRoutingNatChain , 1 , inNatRule ... )
require . NoError ( t , err , "inserting rule should not return error" )
2022-09-05 09:06:35 +02:00
delete ( manager . rules , ipv4 )
delete ( manager . rules , ipv6 )
err = manager . RestoreOrCreateContainers ( )
require . NoError ( t , err , "shouldn't return error" )
err = manager . RemoveRoutingRules ( testCase . inputPair )
require . NoError ( t , err , "shouldn't return error" )
exists , err := iptablesClient . Exists ( iptablesFilterTable , iptablesRoutingForwardingChain , forwardRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesFilterTable , iptablesRoutingForwardingChain )
require . False ( t , exists , "forwarding rule should not exist" )
_ , found := manager . rules [ testCase . ipVersion ] [ forwardRuleKey ]
require . False ( t , found , "forwarding rule should exist in the manager map" )
2022-09-30 11:39:15 +02:00
exists , err = iptablesClient . Exists ( iptablesFilterTable , iptablesRoutingForwardingChain , inForwardRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesFilterTable , iptablesRoutingForwardingChain )
require . False ( t , exists , "income forwarding rule should not exist" )
_ , found = manager . rules [ testCase . ipVersion ] [ inForwardRuleKey ]
require . False ( t , found , "income forwarding rule should exist in the manager map" )
2022-09-05 09:06:35 +02:00
exists , err = iptablesClient . Exists ( iptablesNatTable , iptablesRoutingNatChain , natRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesNatTable , iptablesRoutingNatChain )
require . False ( t , exists , "nat rule should not exist" )
_ , found = manager . rules [ testCase . ipVersion ] [ natRuleKey ]
2022-09-30 11:39:15 +02:00
require . False ( t , found , "nat rule should exist in the manager map" )
exists , err = iptablesClient . Exists ( iptablesNatTable , iptablesRoutingNatChain , inNatRule ... )
require . NoError ( t , err , "should be able to query the iptables %s %s table and %s chain" , testCase . ipVersion , iptablesNatTable , iptablesRoutingNatChain )
require . False ( t , exists , "income nat rule should not exist" )
_ , found = manager . rules [ testCase . ipVersion ] [ inNatRuleKey ]
require . False ( t , found , "income nat rule should exist in the manager map" )
2022-09-05 09:06:35 +02:00
} )
}
}