@@ -67,6 +67,7 @@ const FORWARD_CHAIN_NAME: &CStr = c"forward";
6767const PREROUTING_CHAIN_NAME : & CStr = c"prerouting" ;
6868const MANGLE_CHAIN_NAME : & CStr = c"mangle" ;
6969const NAT_CHAIN_NAME : & CStr = c"nat" ;
70+ const SRCNAT_CHAIN_NAME : & CStr = c"srcnat" ;
7071
7172/// Allows controlling whether firewall rules should have packet counters or not from an env
7273/// variable. Useful for debugging the rules.
@@ -269,6 +270,7 @@ struct PolicyBatch<'a> {
269270 prerouting_chain : Chain < ' a > ,
270271 mangle_chain : Chain < ' a > ,
271272 nat_chain : Chain < ' a > ,
273+ srcnat_chain : Chain < ' a > ,
272274}
273275
274276impl < ' a > PolicyBatch < ' a > {
@@ -314,6 +316,12 @@ impl<'a> PolicyBatch<'a> {
314316 nat_chain. set_policy ( nftnl:: Policy :: Accept ) ;
315317 batch. add ( & nat_chain, nftnl:: MsgType :: Add ) ;
316318
319+ let mut srcnat_chain = Chain :: new ( SRCNAT_CHAIN_NAME , table) ;
320+ srcnat_chain. set_type ( nftnl:: ChainType :: Nat ) ;
321+ srcnat_chain. set_hook ( nftnl:: Hook :: PostRouting , libc:: NF_IP_PRI_NAT_SRC ) ;
322+ srcnat_chain. set_policy ( nftnl:: Policy :: Accept ) ;
323+ batch. add ( & srcnat_chain, nftnl:: MsgType :: Add ) ;
324+
317325 PolicyBatch {
318326 batch,
319327 in_chain,
@@ -322,6 +330,7 @@ impl<'a> PolicyBatch<'a> {
322330 prerouting_chain,
323331 mangle_chain,
324332 nat_chain,
333+ srcnat_chain,
325334 }
326335 }
327336
@@ -333,6 +342,8 @@ impl<'a> PolicyBatch<'a> {
333342 firewall : & Firewall ,
334343 ) -> Result < FinalizedBatch > {
335344 self . add_loopback_rules ( ) ?;
345+ // TODO: if router { .. }
346+ self . add_local_clients_forwaring_rules ( ) ?;
336347 // TODO: Investigate if these rules could/should be handled by PidManager instead.
337348 // It would allow for the firewall to be set up in a secure way even though split tunneling
338349 // does not work, which is okay. It would also allow us to de-duplicate some copy-paste
@@ -507,6 +518,33 @@ impl<'a> PolicyBatch<'a> {
507518 Ok ( ( ) )
508519 }
509520
521+ /// TODO: Don't forget sysctl net.ipv4.forwarding ..
522+ fn add_local_clients_forwaring_rules ( & mut self ) -> Result < ( ) > {
523+ // Forward traffic stemming from (local) private IP ranges to wherever they want.
524+ // TODO: Make sure to document this in nft if we ever add comment expressions..
525+ // LAN -> forward
526+ for net in ALLOWED_LAN_NETS {
527+ let mut forward_from_local_clients = Rule :: new ( & self . forward_chain ) ;
528+ check_net ( & mut forward_from_local_clients, End :: Src , net) ;
529+ add_verdict ( & mut forward_from_local_clients, & Verdict :: Accept ) ;
530+ if * ADD_COUNTERS {
531+ forward_from_local_clients. add_expr ( & nft_expr ! ( counter) ) ;
532+ } ;
533+ self . batch
534+ . add ( & forward_from_local_clients, nftnl:: MsgType :: Add ) ;
535+
536+ // Src Nat
537+ let mut srcnat_rule = Rule :: new ( & self . srcnat_chain ) ;
538+ check_net ( & mut srcnat_rule, End :: Src , net) ;
539+ srcnat_rule. add_expr ( & nft_expr ! ( masquerade) ) ;
540+ if * ADD_COUNTERS {
541+ srcnat_rule. add_expr ( & nft_expr ! ( counter) ) ;
542+ } ;
543+ self . batch . add ( & srcnat_rule, nftnl:: MsgType :: Add ) ;
544+ }
545+ Ok ( ( ) )
546+ }
547+
510548 fn add_dhcp_client_rules ( & mut self ) {
511549 use self :: TransportProtocol :: Udp ;
512550 // Outgoing DHCPv4 request
0 commit comments