@@ -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,51 @@ 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 if let Some ( addr4) = config. outbound_addr4 {
250+ log:: trace!( "Creating IPv4 SNAT rule with outbound address {addr4}" ) ;
251+ hashed_network_chain. build_rule ( VarkRule :: new (
252+ format ! ( "! -d {multicast_dest} -j SNAT --to-source {addr4}" ) ,
253+ Some ( TeardownPolicy :: OnComplete ) ,
254+ ) ) ;
255+ } else {
256+ log:: trace!( "No IPv4 outbound address set, using default MASQUERADE rule" ) ;
257+ hashed_network_chain. build_rule ( VarkRule :: new (
258+ format ! ( "! -d {multicast_dest} -j {MASQUERADE}" ) ,
259+ Some ( TeardownPolicy :: OnComplete ) ,
260+ ) ) ;
261+ }
262+
229263 chains. push ( hashed_network_chain) ;
230264
231265 // POSTROUTING
232266 let mut postrouting_chain =
233267 VarkChain :: new ( conn, NAT . to_string ( ) , POSTROUTING . to_string ( ) , None ) ;
234268 postrouting_chain. build_rule ( VarkRule :: new (
235- format ! ( "-s {network } -j {prefixed_network_hash_name}" ) ,
269+ format ! ( "-s {} -j {}" , config . network , prefixed_network_hash_name ) ,
236270 Some ( TeardownPolicy :: OnComplete ) ,
237271 ) ) ;
238272 chains. push ( postrouting_chain) ;
@@ -272,7 +306,7 @@ pub fn get_network_chains<'a>(
272306 ) ;
273307 netavark_isolation_chain_3. create = true ;
274308
275- if let IsolateOption :: Normal | IsolateOption :: Strict = isolation {
309+ if let IsolateOption :: Normal | IsolateOption :: Strict = config . isolation {
276310 debug ! ( "Add extra isolate rules" ) ;
277311 // NETAVARK_ISOLATION_1
278312 let mut netavark_isolation_chain_1 = VarkChain :: new (
@@ -290,7 +324,7 @@ pub fn get_network_chains<'a>(
290324 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
291325 } ) ;
292326
293- let netavark_isolation_1_target = if let IsolateOption :: Strict = isolation {
327+ let netavark_isolation_1_target = if let IsolateOption :: Strict = config . isolation {
294328 // NETAVARK_ISOLATION_1 -i bridge_name ! -o bridge_name -j NETAVARK_ISOLATION_3
295329 NETAVARK_ISOLATION_3
296330 } else {
@@ -299,15 +333,16 @@ pub fn get_network_chains<'a>(
299333 } ;
300334 netavark_isolation_chain_1. build_rule ( VarkRule {
301335 rule : format ! (
302- "-i {interface_name} ! -o {interface_name} -j {netavark_isolation_1_target}"
336+ "-i {} ! -o {} -j {}" ,
337+ config. interface_name, config. interface_name, netavark_isolation_1_target
303338 ) ,
304339 position : Some ( ind) ,
305340 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
306341 } ) ;
307342
308343 // NETAVARK_ISOLATION_2 -o bridge_name -j DROP
309344 netavark_isolation_chain_2. build_rule ( VarkRule {
310- rule : format ! ( "-o {} -j {}" , interface_name, "DROP" ) ,
345+ rule : format ! ( "-o {} -j {}" , config . interface_name, "DROP" ) ,
311346 position : Some ( ind) ,
312347 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
313348 } ) ;
@@ -328,7 +363,7 @@ pub fn get_network_chains<'a>(
328363
329364 // NETAVARK_ISOLATION_3 -o bridge_name -j DROP
330365 netavark_isolation_chain_3. build_rule ( VarkRule {
331- rule : format ! ( "-o {} -j {}" , interface_name, "DROP" ) ,
366+ rule : format ! ( "-o {} -j {}" , config . interface_name, "DROP" ) ,
332367 position : Some ( ind) ,
333368 td_policy : Some ( TeardownPolicy :: OnComplete ) ,
334369 } ) ;
@@ -375,7 +410,10 @@ pub fn get_network_chains<'a>(
375410 // to gateway when using bridge network with internal dns.
376411 for proto in [ "udp" , "tcp" ] {
377412 netavark_input_chain. build_rule ( VarkRule :: new (
378- format ! ( "-p {proto} -s {network} --dport {dns_port} -j {ACCEPT}" ) ,
413+ format ! (
414+ "-p {proto} -s {} --dport {} -j {ACCEPT}" ,
415+ config. network, config. dns_port
416+ ) ,
379417 Some ( TeardownPolicy :: OnComplete ) ,
380418 ) ) ;
381419 }
@@ -392,14 +430,17 @@ pub fn get_network_chains<'a>(
392430 // Create incoming traffic rule
393431 // CNI did this by IP address, this is implemented per subnet
394432 netavark_forward_chain. build_rule ( VarkRule :: new (
395- format ! ( "-d {network} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" ) ,
433+ format ! (
434+ "-d {} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" ,
435+ config. network
436+ ) ,
396437 Some ( TeardownPolicy :: OnComplete ) ,
397438 ) ) ;
398439
399440 // Create outgoing traffic rule
400441 // CNI did this by IP address, this is implemented per subnet
401442 netavark_forward_chain. build_rule ( VarkRule :: new (
402- format ! ( "-s {network } -j ACCEPT" ) ,
443+ format ! ( "-s {} -j ACCEPT" , config . network ) ,
403444 Some ( TeardownPolicy :: OnComplete ) ,
404445 ) ) ;
405446 chains. push ( netavark_forward_chain) ;
0 commit comments