]> git.ozlabs.org Git - ppp.git/commitdiff
pppd: add sifaddroute and sifdelroute to the ppp api.
authorJaco Kroon <jaco@uls.co.za>
Mon, 10 Mar 2025 15:35:43 +0000 (17:35 +0200)
committerJaco Kroon <jaco@uls.co.za>
Fri, 2 May 2025 10:01:23 +0000 (12:01 +0200)
This includes an implementation on Linux, and a placeholder on Solaris
(which will need to be implemented to make dhcpv6relay module
effective).

Signed-off-by: Jaco Kroon <jaco@uls.co.za>
pppd/pppd.h
pppd/sys-linux.c
pppd/sys-solaris.c

index 786e24f3647dab5c3ed79404bab46f8cec824abb..0a2a24ae14c9cb171d46dbac8de517ef2c9a4a73 100644 (file)
@@ -569,6 +569,10 @@ typedef void (*event_cb)(int fd, void* ctx); /* callback signature */
 void add_fd_callback(int, event_cb, void*); /* add fd with callback */
 void remove_fd(int);   /* Remove fd from set to wait for */
 
+/* route management, be sure that prefix points to a correct buffer */
+int sifaddroute(int family, const void* prefix, uint8_t len, unsigned metric);
+int sifdelroute(int family, const void* prefix, uint8_t len, unsigned metric);
+
 #ifdef __cplusplus
 }
 #endif
index 3c757ee7d2ff61f92081121c3d1d92c50bf5d997..51fbe29d2a11368ca9ef866ca7238825fc83df27 100644 (file)
@@ -2091,7 +2091,7 @@ int have_route_to(u_int32_t addr)
  * Try using netlink to add/remove routes.
  */
 static
-int _route_netlink(const char* op_fam, int operation, int family, unsigned metric)
+int _route_netlink(const char* op_fam, int operation, int family, unsigned metric, const void* prefix, uint8_t len)
 {
     struct {
        struct nlmsghdr nlh;
@@ -2104,12 +2104,17 @@ int _route_netlink(const char* op_fam, int operation, int family, unsigned metri
            struct rtattr rta;
            unsigned val;
        } metric;
+       struct {
+           struct rtattr rta;
+           unsigned char ipdata[16]; /* IPv6 MAX */
+       } prefix;
     } nlreq;
     int resp;
+    size_t txsz = sizeof(nlreq) - sizeof(nlreq.prefix);
+    char in6addr[INET6_ADDRSTRLEN];
 
     memset(&nlreq, 0, sizeof(nlreq));
 
-    nlreq.nlh.nlmsg_len = sizeof(nlreq);
     nlreq.nlh.nlmsg_type = operation;
     nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
     if (operation == RTM_NEWROUTE)
@@ -2129,19 +2134,59 @@ int _route_netlink(const char* op_fam, int operation, int family, unsigned metri
     nlreq.metric.rta.rta_type = RTA_PRIORITY;
     nlreq.metric.val = metric;
 
-    resp = rtnetlink_msg(op_fam, NULL, &nlreq, sizeof(nlreq), NULL, NULL, 0);
+    if (prefix) {
+       char nbytes;
+       switch (family) {
+       case AF_INET: nbytes = 4; break;
+       case AF_INET6: nbytes = 16; break;
+       default: error("Unable to add route given that address family isn't known and prefix was specified."); return 0;
+       }
+       nlreq.rtmsg.rtm_dst_len = len;
+       nlreq.prefix.rta.rta_type = RTA_DST;
+       nlreq.prefix.rta.rta_len = sizeof(nlreq.prefix.rta) + nbytes;
+       memcpy(nlreq.prefix.ipdata, prefix, nbytes);
+
+       txsz += nlreq.prefix.rta.rta_len;
+    }
+
+    nlreq.nlh.nlmsg_len = txsz;
+    resp = rtnetlink_msg(op_fam, NULL, &nlreq, txsz, NULL, NULL, 0);
+
     /* In some cases the interface could be down already from kernel perspective,
      * and routes already removed resulting in errno=ESRCH, treat as success */
     if (resp == 0 || operation == RTM_DELROUTE && -resp == ESRCH)
        return 1; /* success */
 
-    error("Unable to %s %s default route: %s", operation == RTM_NEWROUTE ? "add" : "remove",
+    error("Unable to %s %s %s route: %s", operation == RTM_NEWROUTE ? "add" : "remove",
            family == AF_INET ? "IPv4" : "IPv6",
+           prefix ? inet_ntop(family, prefix, in6addr, sizeof(in6addr)) : "default",
            resp < 0 ? strerror(-resp) : "Netlink error");
 
     return 0;
 }
-#define route_netlink(operation, family, metric) _route_netlink(#operation "/" #family, operation, family, metric)
+#define route_netlink(operation, family, metric, prefix, length) _route_netlink(#operation "/" #family, operation, family, metric, prefix, length)
+
+/********************************************************************
+ * sifaddroute - add a non-default route to the system through the ppp interface.
+ * It's the caller responsiblity to ensure that prefix points to a buffer of appriate size:
+ * AF_INET => 4 bytes
+ * AF_INET6 => 16 bytes
+ */
+int sifaddroute(int family, const void* prefix, uint8_t len, unsigned metric)
+{
+    return route_netlink(RTM_NEWROUTE, family, metric, prefix, len);
+}
+
+/********************************************************************
+ * sifdelroute - remove a non-default route to the system through the ppp interface.
+ * It's the caller responsiblity to ensure that prefix points to a buffer of appriate size:
+ * AF_INET => 4 bytes
+ * AF_INET6 => 16 bytes
+ */
+int sifdelroute(int family, const void* prefix, uint8_t len, unsigned metric)
+{
+    return route_netlink(RTM_DELROUTE, family, metric, prefix, len);
+}
 
 /********************************************************************
  *
@@ -2150,7 +2195,7 @@ int _route_netlink(const char* op_fam, int operation, int family, unsigned metri
 int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
 {
     /* try appending using netlink first */
-    if (route_netlink(RTM_NEWROUTE, AF_INET, dfl_route_metric))
+    if (route_netlink(RTM_NEWROUTE, AF_INET, dfl_route_metric, NULL, 0))
        return 1;
 
     /* ok, that failed, let's see if we can use ioctl */
@@ -2186,7 +2231,7 @@ int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
 int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
 {
     /* try removing using netlink first */
-    if (route_netlink(RTM_DELROUTE, AF_INET, dfl_route_metric))
+    if (route_netlink(RTM_DELROUTE, AF_INET, dfl_route_metric, NULL, 0))
        return 1;
 
     /* ok, that failed, let's see if we can use ioctl */
@@ -2227,7 +2272,7 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
 int sif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
 {
     /* try appending using netlink first */
-    if (route_netlink(RTM_NEWROUTE, AF_INET6, dfl_route6_metric))
+    if (route_netlink(RTM_NEWROUTE, AF_INET6, dfl_route6_metric, NULL, 0))
        return 1;
 
     /* ok, that failed, let's see if we can use ioctl */
@@ -2258,7 +2303,7 @@ int sif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
 int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
 {
     /* try removing using netlink first */
-    if (route_netlink(RTM_DELROUTE, AF_INET6, dfl_route6_metric))
+    if (route_netlink(RTM_DELROUTE, AF_INET6, dfl_route6_metric, NULL, 0))
        return 1;
 
     /* ok, that failed, let's see if we can use ioctl */
index 4e076bf0813ff6553ac0b41388e498910950018e..51f284f0b3e08ac9c5c8b073f054e0e8a63a1200 100644 (file)
@@ -1664,6 +1664,30 @@ cifaddr(int u, u_int32_t o, u_int32_t h)
     return 1;
 }
 
+/********************************************************************
+ * sifaddroute - add a non-default route to the system through the ppp interface.
+ * It's the caller responsiblity to ensure that prefix points to a buffer of appriate size:
+ * AF_INET => 4 bytes
+ * AF_INET6 => 16 bytes
+ */
+int sifaddroute(int family, const void* prefix, uint8_t len, unsigned metric)
+{
+    error("Implementation on sifaddroute for solaris is lacking.");
+    return 0;
+}
+
+/********************************************************************
+ * sifdelroute - remove a non-default route to the system through the ppp interface.
+ * It's the caller responsiblity to ensure that prefix points to a buffer of appriate size:
+ * AF_INET => 4 bytes
+ * AF_INET6 => 16 bytes
+ */
+int sifdelroute(int family, const void* prefix, uint8_t len, unsigned metric)
+{
+    error("Implementation on sifaddroute for solaris is lacking.");
+    return 0;
+}
+
 /*
  * sifdefaultroute - assign a default route through the address given.
  */