From: Jaco Kroon Date: Mon, 10 Mar 2025 15:35:43 +0000 (+0200) Subject: pppd: add sifaddroute and sifdelroute to the ppp api. X-Git-Url: https://git.ozlabs.org/?a=commitdiff_plain;h=b68270e54e813afd871b82dd42ba3aeccaa03822;p=ppp.git pppd: add sifaddroute and sifdelroute to the ppp api. 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 --- diff --git a/pppd/pppd.h b/pppd/pppd.h index 786e24f..0a2a24a 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -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 diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 3c757ee..51fbe29 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -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 */ diff --git a/pppd/sys-solaris.c b/pppd/sys-solaris.c index 4e076bf..51f284f 100644 --- a/pppd/sys-solaris.c +++ b/pppd/sys-solaris.c @@ -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. */