@@ -7,7 +7,7 @@ use crate::network::internal_types::{IsolateOption, PortForwardConfig};
77use ipnet:: IpNet ;
88use iptables:: IPTables ;
99use log:: debug;
10- use std:: net:: IpAddr ;
10+ use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr } ;
1111
1212// Chain names
1313const NAT : & str = "nat" ;
@@ -66,6 +66,7 @@ impl VarkRule {
6666 & self . rule
6767 }
6868}
69+
6970// Varkchain is an iptable chain with extra info
7071pub struct VarkChain < ' a > {
7172 // name of chain
@@ -192,17 +193,24 @@ pub fn create_network_chains(chains: Vec<VarkChain<'_>>) -> NetavarkResult<()> {
192193 Ok ( ( ) )
193194}
194195
195- pub fn get_network_chains < ' a > (
196- conn : & ' a IPTables ,
197- network : IpNet ,
198- network_hash_name : & ' a str ,
199- is_ipv6 : bool ,
200- interface_name : String ,
201- isolation : IsolateOption ,
202- dns_port : u16 ,
203- ) -> Vec < VarkChain < ' a > > {
196+ pub struct NetworkChainConfig {
197+ pub network : IpNet ,
198+ pub network_hash_name : String ,
199+ pub interface_name : String ,
200+ pub isolation : IsolateOption ,
201+ pub dns_port : u16 ,
202+ pub outbound_addr4 : Option < Ipv4Addr > ,
203+ pub outbound_addr6 : Option < Ipv6Addr > ,
204+ }
205+
206+ pub fn get_network_chains ( conn : & IPTables , config : NetworkChainConfig ) -> Vec < VarkChain < ' _ > > {
204207 let mut chains = Vec :: new ( ) ;
205- let prefixed_network_hash_name = format ! ( "{}-{}" , "NETAVARK" , network_hash_name) ;
208+ let prefixed_network_hash_name = format ! ( "{}-{}" , "NETAVARK" , config. network_hash_name) ;
209+
210+ let is_ipv6 = match config. network {
211+ IpNet :: V4 ( _) => false ,
212+ IpNet :: V6 ( _) => true ,
213+ } ;
206214
207215 // NETAVARK-HASH
208216 let mut hashed_network_chain = VarkChain :: new (
@@ -214,25 +222,52 @@ pub fn get_network_chains<'a>(
214222 hashed_network_chain. create = true ;
215223
216224 hashed_network_chain. build_rule ( VarkRule :: new (
217- format ! ( "-d {network } -j {ACCEPT}" ) ,
225+ format ! ( "-d {} -j {}" , config . network , ACCEPT ) ,
218226 Some ( TeardownPolicy :: OnComplete ) ,
219227 ) ) ;
220228
221229 let mut multicast_dest = MULTICAST_NET_V4 ;
222230 if is_ipv6 {
223231 multicast_dest = MULTICAST_NET_V6 ;
224232 }
225- hashed_network_chain. build_rule ( VarkRule :: new (
226- format ! ( "! -d {multicast_dest} -j {MASQUERADE}" ) ,
227- Some ( TeardownPolicy :: OnComplete ) ,
228- ) ) ;
233+
234+ // Use appropriate outbound address based on subnet type
235+ if is_ipv6 {
236+ if let Some ( addr6) = config. outbound_addr6 {
237+ log:: trace!( "Creating IPv6 SNAT rule with outbound address {}" , addr6) ;
238+ hashed_network_chain. build_rule ( VarkRule :: new (
239+ format ! ( "! -d {multicast_dest} -j SNAT --to-source {}" , addr6) ,
240+ Some ( TeardownPolicy :: OnComplete ) ,
241+ ) ) ;
242+ } else {
243+ log:: trace!( "No IPv6 outbound address set, using default MASQUERADE rule" ) ;
244+ hashed_network_chain. build_rule ( VarkRule :: new (
245+ format ! ( "! -d {multicast_dest} -j {MASQUERADE}" ) ,
246+ Some ( TeardownPolicy :: OnComplete ) ,
247+ ) ) ;
248+ }
249+ } else {
250+ if let Some ( addr4) = config. outbound_addr4 {
251+ log:: trace!( "Creating IPv4 SNAT rule with outbound address {}" , addr4) ;
252+ hashed_network_chain. build_rule ( VarkRule :: new (
253+ format ! ( "! -d {multicast_dest} -j SNAT --to-source {}" , addr4) ,
254+ Some ( TeardownPolicy :: OnComplete ) ,
255+ ) ) ;
256+ } else {
257+ log:: trace!( "No IPv4 outbound address set, using default MASQUERADE rule" ) ;
258+ hashed_network_chain. build_rule ( VarkRule :: new (
259+ format ! ( "! -d {multicast_dest} -j {MASQUERADE}" ) ,
260+ Some ( TeardownPolicy :: OnComplete ) ,
261+ ) ) ;
262+ }
263+ }
229264 chains. push ( hashed_network_chain) ;
230265
231266 // POSTROUTING
232267 let mut postrouting_chain =
233268 VarkChain :: new ( conn, NAT . to_string ( ) , POSTROUTING . to_string ( ) , None ) ;
234269 postrouting_chain. build_rule ( VarkRule :: new (
235- format ! ( "-s {network } -j {prefixed_network_hash_name}" ) ,
270+ format ! ( "-s {} -j {}" , config . network , prefixed_network_hash_name ) ,
236271 Some ( TeardownPolicy :: OnComplete ) ,
237272 ) ) ;
238273 chains. push ( postrouting_chain) ;
@@ -272,7 +307,7 @@ pub fn get_network_chains<'a>(
272307 ) ;
273308 netavark_isolation_chain_3. create = true ;
274309
275- if let IsolateOption :: Normal | IsolateOption :: Strict = isolation {
310+ if let IsolateOption :: Normal | IsolateOption :: Strict = config . isolation {
276311 debug ! ( "Add extra isolate rules" ) ;
277312 // NETAVARK_ISOLATION_1
278313 let mut netavark_isolation_chain_1 = VarkChain :: new (
@@ -290,7 +325,7 @@ pub fn get_network_chains<'a>(
290325 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
291326 } ) ;
292327
293- let netavark_isolation_1_target = if let IsolateOption :: Strict = isolation {
328+ let netavark_isolation_1_target = if let IsolateOption :: Strict = config . isolation {
294329 // NETAVARK_ISOLATION_1 -i bridge_name ! -o bridge_name -j NETAVARK_ISOLATION_3
295330 NETAVARK_ISOLATION_3
296331 } else {
@@ -299,15 +334,16 @@ pub fn get_network_chains<'a>(
299334 } ;
300335 netavark_isolation_chain_1. build_rule ( VarkRule {
301336 rule : format ! (
302- "-i {interface_name} ! -o {interface_name} -j {netavark_isolation_1_target}"
337+ "-i {} ! -o {} -j {}" ,
338+ config. interface_name, config. interface_name, netavark_isolation_1_target
303339 ) ,
304340 position : Some ( ind) ,
305341 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
306342 } ) ;
307343
308344 // NETAVARK_ISOLATION_2 -o bridge_name -j DROP
309345 netavark_isolation_chain_2. build_rule ( VarkRule {
310- rule : format ! ( "-o {} -j {}" , interface_name, "DROP" ) ,
346+ rule : format ! ( "-o {} -j {}" , config . interface_name, "DROP" ) ,
311347 position : Some ( ind) ,
312348 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
313349 } ) ;
@@ -328,7 +364,7 @@ pub fn get_network_chains<'a>(
328364
329365 // NETAVARK_ISOLATION_3 -o bridge_name -j DROP
330366 netavark_isolation_chain_3. build_rule ( VarkRule {
331- rule : format ! ( "-o {} -j {}" , interface_name, "DROP" ) ,
367+ rule : format ! ( "-o {} -j {}" , config . interface_name, "DROP" ) ,
332368 position : Some ( ind) ,
333369 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
334370 } ) ;
@@ -375,7 +411,10 @@ pub fn get_network_chains<'a>(
375411 // to gateway when using bridge network with internal dns.
376412 for proto in [ "udp" , "tcp" ] {
377413 netavark_input_chain. build_rule ( VarkRule :: new (
378- format ! ( "-p {proto} -s {network} --dport {dns_port} -j {ACCEPT}" ) ,
414+ format ! (
415+ "-p {proto} -s {} --dport {} -j {ACCEPT}" ,
416+ config. network, config. dns_port
417+ ) ,
379418 Some ( TeardownPolicy :: OnComplete ) ,
380419 ) ) ;
381420 }
@@ -392,14 +431,17 @@ pub fn get_network_chains<'a>(
392431 // Create incoming traffic rule
393432 // CNI did this by IP address, this is implemented per subnet
394433 netavark_forward_chain. build_rule ( VarkRule :: new (
395- format ! ( "-d {network} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" ) ,
434+ format ! (
435+ "-d {} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" ,
436+ config. network
437+ ) ,
396438 Some ( TeardownPolicy :: OnComplete ) ,
397439 ) ) ;
398440
399441 // Create outgoing traffic rule
400442 // CNI did this by IP address, this is implemented per subnet
401443 netavark_forward_chain. build_rule ( VarkRule :: new (
402- format ! ( "-s {network } -j ACCEPT" ) ,
444+ format ! ( "-s {} -j ACCEPT" , config . network ) ,
403445 Some ( TeardownPolicy :: OnComplete ) ,
404446 ) ) ;
405447 chains. push ( netavark_forward_chain) ;
0 commit comments