@@ -1350,6 +1350,103 @@ func (r *router) UpdateSet(set firewall.Set, prefixes []netip.Prefix) error {
13501350 return nil
13511351}
13521352
1353+ // AddInboundDNAT adds an inbound DNAT rule redirecting traffic from NetBird peers to local services.
1354+ func (r * router ) AddInboundDNAT (localAddr netip.Addr , protocol firewall.Protocol , sourcePort , targetPort uint16 ) error {
1355+ ruleID := fmt .Sprintf ("inbound-dnat-%s-%s-%d-%d" , localAddr .String (), protocol , sourcePort , targetPort )
1356+
1357+ if _ , exists := r .rules [ruleID ]; exists {
1358+ return nil
1359+ }
1360+
1361+ protoNum , err := protoToInt (protocol )
1362+ if err != nil {
1363+ return fmt .Errorf ("convert protocol to number: %w" , err )
1364+ }
1365+
1366+ exprs := []expr.Any {
1367+ & expr.Meta {Key : expr .MetaKeyIIFNAME , Register : 1 },
1368+ & expr.Cmp {
1369+ Op : expr .CmpOpEq ,
1370+ Register : 1 ,
1371+ Data : ifname (r .wgIface .Name ()),
1372+ },
1373+ & expr.Meta {Key : expr .MetaKeyL4PROTO , Register : 2 },
1374+ & expr.Cmp {
1375+ Op : expr .CmpOpEq ,
1376+ Register : 2 ,
1377+ Data : []byte {protoNum },
1378+ },
1379+ & expr.Payload {
1380+ DestRegister : 3 ,
1381+ Base : expr .PayloadBaseTransportHeader ,
1382+ Offset : 2 ,
1383+ Len : 2 ,
1384+ },
1385+ & expr.Cmp {
1386+ Op : expr .CmpOpEq ,
1387+ Register : 3 ,
1388+ Data : binaryutil .BigEndian .PutUint16 (sourcePort ),
1389+ },
1390+ }
1391+
1392+ exprs = append (exprs , applyPrefix (netip .PrefixFrom (localAddr , 32 ), false )... )
1393+
1394+ exprs = append (exprs ,
1395+ & expr.Immediate {
1396+ Register : 1 ,
1397+ Data : localAddr .AsSlice (),
1398+ },
1399+ & expr.Immediate {
1400+ Register : 2 ,
1401+ Data : binaryutil .BigEndian .PutUint16 (targetPort ),
1402+ },
1403+ & expr.NAT {
1404+ Type : expr .NATTypeDestNAT ,
1405+ Family : uint32 (nftables .TableFamilyIPv4 ),
1406+ RegAddrMin : 1 ,
1407+ RegProtoMin : 2 ,
1408+ RegProtoMax : 0 ,
1409+ },
1410+ )
1411+
1412+ dnatRule := & nftables.Rule {
1413+ Table : r .workTable ,
1414+ Chain : r .chains [chainNameRoutingRdr ],
1415+ Exprs : exprs ,
1416+ UserData : []byte (ruleID ),
1417+ }
1418+ r .conn .AddRule (dnatRule )
1419+
1420+ if err := r .conn .Flush (); err != nil {
1421+ return fmt .Errorf ("add inbound DNAT rule: %w" , err )
1422+ }
1423+
1424+ r .rules [ruleID ] = dnatRule
1425+
1426+ return nil
1427+ }
1428+
1429+ // RemoveInboundDNAT removes an inbound DNAT rule.
1430+ func (r * router ) RemoveInboundDNAT (localAddr netip.Addr , protocol firewall.Protocol , sourcePort , targetPort uint16 ) error {
1431+ if err := r .refreshRulesMap (); err != nil {
1432+ return fmt .Errorf (refreshRulesMapError , err )
1433+ }
1434+
1435+ ruleID := fmt .Sprintf ("inbound-dnat-%s-%s-%d-%d" , localAddr .String (), protocol , sourcePort , targetPort )
1436+
1437+ if rule , exists := r .rules [ruleID ]; exists {
1438+ if err := r .conn .DelRule (rule ); err != nil {
1439+ return fmt .Errorf ("delete inbound DNAT rule %s: %w" , ruleID , err )
1440+ }
1441+ if err := r .conn .Flush (); err != nil {
1442+ return fmt .Errorf ("flush delete inbound DNAT rule: %w" , err )
1443+ }
1444+ delete (r .rules , ruleID )
1445+ }
1446+
1447+ return nil
1448+ }
1449+
13531450// applyNetwork generates nftables expressions for networks (CIDR) or sets
13541451func (r * router ) applyNetwork (
13551452 network firewall.Network ,
0 commit comments