netifd: iprule add sport and dport
authoregc112 <[email protected]>
Sun, 20 Apr 2025 11:05:11 +0000 (13:05 +0200)
committerRobert Marko <[email protected]>
Fri, 23 May 2025 11:18:40 +0000 (13:18 +0200)
Maintainer: @nbd, @robimarko

I was missing the ip rules for `sport` and `dport` in netifd and although I have a working C knowledge, I have little netlink knowledge and it is the first time I looked into netifd but after some research I could come up with a working patch to implement `option sport` and `option dport`.

I hope you can have a look and implement these useful options.

Run tested: Dynalink DL-WRX36 (ipq8074) running Main Snapshot r29276-963d320086 20-apr-2025

Example 1 sport:
```
config rule
option src '192.168.9.23/32'
option sport '1194'
option lookup 'main'
```
Result:
```
root@DL-WRX36:~# ip ru
0:      from all lookup local
1:      from 192.168.9.23 sport 1194 lookup main
```

Example 2  sport range:
```
config rule
option src '192.168.9.23/32'
option sport '1194-1195'
option lookup 'main'
```
Result:
```
root@DL-WRX36:~# ip ru
0:      from all lookup local
1:      from 192.168.9.23 sport 1194-1195 lookup main
```

Example 3 dport:
```
config rule
option src '192.168.9.23/32'
option dport '1294'
option lookup 'main'
```
Result:
```
root@DL-WRX36:~# ip ru
0:      from all lookup local
1:      from 192.168.9.23 dport 1294 lookup main
```

Example 4  dport range:
```
config rule
option src '192.168.9.23/32'
option dport '1294-1295'
option lookup 'main'
```
Result:
```
root@DL-WRX36:~# ip ru
0:      from all lookup local
1:      from 192.168.9.23 dport 1294-1295 lookup main
```
Example 5 sport dport:
```
config rule
option src '192.168.9.23/32'
option sport '1194-1195'
option dport '1294-1295'
option lookup 'main'
```
Result:
```
root@DL-WRX36:~# ip ru
0:      from all lookup local
1:      from 192.168.9.23 sport 1194-1195 dport 1294-1295 lookup main
```

Signed-off-by: Erik Conijn <[email protected]>
Link: https://github.com/openwrt/netifd/pull/47
Signed-off-by: Robert Marko <[email protected]>
iprule.c
iprule.h
system-linux.c

index f6f9d4ee7ec90d6c36c8dff770a408652997a02a..c2009c877f1b1cbf3272c61011a529fae715b468 100644 (file)
--- a/iprule.c
+++ b/iprule.c
@@ -46,6 +46,8 @@ enum {
        RULE_SUP_PREFIXLEN,
        RULE_UIDRANGE,
        RULE_IPPROTO,
+       RULE_SPORT,
+       RULE_DPORT,
        RULE_DISABLED,
        __RULE_MAX
 };
@@ -65,6 +67,8 @@ static const struct blobmsg_policy rule_attr[__RULE_MAX] = {
        [RULE_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_STRING },
        [RULE_GOTO]   = { .name = "goto", .type = BLOBMSG_TYPE_INT32 },
        [RULE_IPPROTO]  = { .name = "ipproto", .type = BLOBMSG_TYPE_STRING },
+       [RULE_SPORT]  = { .name = "sport", .type = BLOBMSG_TYPE_STRING },
+       [RULE_DPORT]  = { .name = "dport", .type = BLOBMSG_TYPE_STRING },
        [RULE_DISABLED] = { .name = "disabled", .type = BLOBMSG_TYPE_BOOL },
 };
 
@@ -319,6 +323,30 @@ iprule_add(struct blob_attr *attr, bool v6)
                rule->flags |= IPRULE_IPPROTO;
        }
 
+       if ((cur = tb[RULE_SPORT]) != NULL) {
+               int ret = sscanf(blobmsg_get_string(cur), "%u-%u", &rule->sport_start, &rule->sport_end);
+
+               if (ret == 1)
+                       rule->sport_end = rule->sport_start;
+               else if (ret != 2) {
+                       D(INTERFACE, "Failed to parse sport range: %s", (char *) blobmsg_data(cur));
+                       goto error;
+               }
+               rule->flags |= IPRULE_SPORT;
+       }
+
+       if ((cur = tb[RULE_DPORT]) != NULL) {
+               int ret = sscanf(blobmsg_get_string(cur), "%u-%u", &rule->dport_start, &rule->dport_end);
+
+               if (ret == 1)
+                       rule->dport_end = rule->dport_start;
+               else if (ret != 2) {
+                       D(INTERFACE, "Failed to parse dport range: %s", (char *) blobmsg_data(cur));
+                       goto error;
+               }
+               rule->flags |= IPRULE_DPORT;
+       }
+
        vlist_add(&iprules, &rule->node, rule);
        return;
 
index 56b9998b3a295184d1d73b1c903edf5e55f9d291..19d24fbb020f38c8000ea5faeb7c06549493a46d 100644 (file)
--- a/iprule.h
+++ b/iprule.h
@@ -69,6 +69,12 @@ enum iprule_flags {
 
        /* rule specifies ipproto */
        IPRULE_IPPROTO          = (1 << 15),
+
+       /* rule specifies sport */
+       IPRULE_SPORT            = (1 << 16),
+
+       /* rule specifies dport */
+       IPRULE_DPORT            = (1 << 17),
 };
 
 struct iprule {
@@ -113,6 +119,10 @@ struct iprule {
        unsigned int action;
        unsigned int gotoid;
        unsigned int ipproto;
+       unsigned int sport_start;
+       unsigned int sport_end;
+       unsigned int dport_start;
+       unsigned int dport_end;
 };
 
 extern struct vlist_tree iprules;
index 5c525ce8f2649e73288a97eb882fc169d3d56a19..29f9b4d8de4f92997626338e97ea944369695842 100644 (file)
@@ -3690,6 +3690,24 @@ static int system_iprule(struct iprule *rule, int cmd)
        if (rule->flags & IPRULE_IPPROTO)
                nla_put_u8(msg, FRA_IP_PROTO, rule->ipproto);
 
+       if (rule->flags & IPRULE_SPORT) {
+               struct fib_rule_port_range sportrange = {
+                       .start = rule->sport_start,
+                       .end = rule->sport_end
+               };
+
+               nla_put(msg, FRA_SPORT_RANGE, sizeof(sportrange), &sportrange);
+       }
+
+       if (rule->flags & IPRULE_DPORT) {
+               struct fib_rule_port_range dportrange = {
+                       .start = rule->dport_start,
+                       .end = rule->dport_end
+               };
+
+               nla_put(msg, FRA_DPORT_RANGE, sizeof(dportrange), &dportrange);
+       }
+
        return system_rtnl_call(msg);
 }