Applied, thanks! Damien Zammit, le lun. 29 août 2022 10:30:04 +0000, a ecrit: > Using a new client side <net/route.h> > I was able to clean up the existing options.c in pfinet > and add two new ioctls for adding/deleting network routes. > > #ifndef NET_ROUTE_H_ > #define NET_ROUTE_H_ > > #include <sys/socket.h> > #include <netinet/in.h> > #include <arpa/inet.h> > > #define _IOT_ifrtreq _IOT (_IOTS(char), IFNAMSIZ, _IOTS(int), 10, 0, 0) > > /* move to bits/ioctl.h */ > #define SIOCADDRT _IOW('i', 10, struct ifrtreq) > #define SIOCDELRT _IOW('i', 11, struct ifrtreq) > > struct ifrtreq { > char ifname[IFNAMSIZ]; > in_addr_t rt_dest; > in_addr_t rt_mask; > in_addr_t rt_gateway; > int rt_flags; > int rt_metric; > int rt_mtu; > int rt_window; > int rt_irtt; > int rt_tos; > int rt_class; > }; > > #endif > > --- > hurd/iioctl.defs | 17 ++- > hurd/ioctl_types.h | 15 +++ > pfinet/iioctl-ops.c | 280 ++++++++++++++++++++++++++++++++++++++++++++ > pfinet/options.c | 122 ++++--------------- > 4 files changed, 332 insertions(+), 102 deletions(-) > > diff --git a/hurd/iioctl.defs b/hurd/iioctl.defs > index dfa89033f..6701d8ec7 100644 > --- a/hurd/iioctl.defs > +++ b/hurd/iioctl.defs > @@ -40,9 +40,24 @@ type ifname_t = array[16] of char; /* IFNAMSIZ is 16. */ > definition of _IOT_ifreq in <net/if.h>. */ > type sockaddr_t = struct[16] of char; /* sizeof(struct sockaddr) is > 16. */ > > +/* This is the struct srtentry from <net/route.h>. */ > +type srtentry_t = struct[40] of char; /* sizeof(struct srtentry) is > 40. */ > + > skip; skip; skip; skip; /* 0 1 2 3 unused */ > skip; skip; skip; skip; /* 4 5 6 7 unused */ > -skip; skip; skip; skip; /* 8 9 10 11 unused */ > +skip; skip; /* 8 9 unused */ > + > +/* 10 SIOCADDRT */ > +routine iioctl_siocaddrt ( > + reqport: io_t; > + ifnam: ifname_t; > + route: srtentry_t); > + > +/* 11 SIOCDELRT */ > +routine iioctl_siocdelrt ( > + reqport: io_t; > + ifnam: ifname_t; > + route: srtentry_t); > > /* 12 SIOCSIFADDR */ > routine iioctl_siocsifaddr ( > diff --git a/hurd/ioctl_types.h b/hurd/ioctl_types.h > index 8baa36040..1e22fe597 100644 > --- a/hurd/ioctl_types.h > +++ b/hurd/ioctl_types.h > @@ -30,4 +30,19 @@ typedef struct winsize winsize_t; > typedef struct sockaddr sockaddr_t; > typedef char ifname_t[16]; > > +#include <stdint.h> > +struct srtentry { > + uint32_t rt_dest; > + uint32_t rt_mask; > + uint32_t rt_gateway; > + int rt_flags; > + int rt_metric; > + int rt_mtu; > + int rt_window; > + int rt_irtt; > + int rt_tos; > + int rt_class; > +}; > + > +typedef struct srtentry srtentry_t; > #endif /* hurd/ioctl_types.h */ > diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c > index 191c65913..3185c8141 100644 > --- a/pfinet/iioctl-ops.c > +++ b/pfinet/iioctl-ops.c > @@ -22,9 +22,14 @@ > > #include <linux/netdevice.h> > #include <linux/notifier.h> > +#include <linux/inetdevice.h> > +#include <linux/ip.h> > +#include <linux/route.h> > +#include <linux/rtnetlink.h> > > #include "iioctl_S.h" > #include <netinet/in.h> > +#include <arpa/inet.h> > #include <fcntl.h> > #include <string.h> > #include <unistd.h> > @@ -32,9 +37,14 @@ > #include <sys/mman.h> > #include <hurd/fshelp.h> > > +#include <sys/socket.h> > #include <sys/ioctl.h> > #include <net/if.h> > #include <net/sock.h> > +#include <hurd/ioctl_types.h> > +#include <net/route.h> > +#include <net/ip_fib.h> > +#include <net/addrconf.h> > > extern struct notifier_block *netdev_chain; > > @@ -64,6 +74,226 @@ struct device *get_dev (const char *name) > return dev; > } > > +static uint32_t > +get_gateway(struct device *dev) > +{ > + uint32_t gateway = 0; > + struct rt_key key = { 0 }; > + struct fib_result res; > + > + /* Get gateway */ > + gateway = INADDR_NONE; > + key.oif = dev->ifindex; > + if (! main_table->tb_lookup (main_table, &key, &res) > + && FIB_RES_GW(res) != INADDR_ANY) > + gateway = FIB_RES_GW (res); > + return gateway; > +} > + > +/* This code is cobbled together from what > + * the SIOCADDRT ioctl code does, and from the apparent functionality > + * of the "netlink" layer from perusing a little. > + */ > +static error_t > +delete_gateway(struct device *dev, in_addr_t dst, in_addr_t mask, in_addr_t > gw) > +{ > + error_t err; > + struct kern_rta rta; > + struct > + { > + struct nlmsghdr nlh; > + struct rtmsg rtm; > + } req; > + struct fib_table *tb; > + > + if (bad_mask (mask, dst)) > + return EINVAL; > + > + req.nlh.nlmsg_pid = 0; > + req.nlh.nlmsg_seq = 0; > + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); > + > + memset (&req.rtm, 0, sizeof req.rtm); > + memset (&rta, 0, sizeof rta); > + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; > + req.rtm.rtm_type = RTN_UNICAST; > + req.rtm.rtm_protocol = RTPROT_BOOT; > + req.rtm.rtm_dst_len = inet_mask_len(mask); > + > + /* Delete any existing default route on configured device */ > + req.nlh.nlmsg_type = RTM_DELROUTE; > + req.nlh.nlmsg_flags = 0; > + rta.rta_oif = &dev->ifindex; > + rta.rta_dst = &dst; > + rta.rta_gw = &gw; > + tb = fib_get_table (req.rtm.rtm_table); > + if (tb) > + { > + err = - (*tb->tb_delete) > + (tb, &req.rtm, &rta, &req.nlh, 0); > + if (err && err != ESRCH) > + return err; > + err = 0; > + } > + return err; > +} > + > +static error_t > +add_gateway(struct device *dev, in_addr_t dst, in_addr_t mask, in_addr_t gw) > +{ > + error_t err; > + struct kern_rta rta; > + struct > + { > + struct nlmsghdr nlh; > + struct rtmsg rtm; > + } req = {0}; > + struct fib_table *tb; > + > + if (bad_mask (mask, dst)) > + return EINVAL; > + > + req.nlh.nlmsg_pid = 0; > + req.nlh.nlmsg_seq = 0; > + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); > + > + memset (&req.rtm, 0, sizeof req.rtm); > + memset (&rta, 0, sizeof rta); > + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; > + req.rtm.rtm_type = RTN_UNICAST; > + req.rtm.rtm_protocol = RTPROT_BOOT; > + req.rtm.rtm_dst_len = inet_mask_len(mask); > + > + /* Add a gateway */ > + rta.rta_oif = &dev->ifindex; > + rta.rta_dst = &dst; > + rta.rta_gw = &gw; > + req.nlh.nlmsg_type = RTM_NEWROUTE; > + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; > + tb = fib_new_table (req.rtm.rtm_table); > + err = (!tb ? ENOBUFS > + : - (*tb->tb_insert) (tb, &req.rtm, &rta, &req.nlh, 0)); > + return err; > +} > + > +/* Setup a static route (required for e.g. DHCP) */ > +static error_t > +add_static_route(struct device *dev, in_addr_t dst, in_addr_t mask) > +{ > + error_t err; > + struct kern_rta rta; > + struct > + { > + struct nlmsghdr nlh; > + struct rtmsg rtm; > + } req; > + struct fib_table *tb; > + > + if (bad_mask (mask, dst)) > + return EINVAL; > + > + if (!dev->name) > + return ENODEV; > + > + /* Simulate the SIOCADDRT behavior. */ > + memset (&req.rtm, 0, sizeof req.rtm); > + memset (&rta, 0, sizeof rta); > + > + /* Append this routing for addr. By this way we can always send > + dhcp messages (e.g dhcp renew). */ > + req.nlh.nlmsg_type = RTM_NEWROUTE; > + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_APPEND; > + req.rtm.rtm_protocol = RTPROT_BOOT; > + req.rtm.rtm_scope = RT_SCOPE_LINK; > + req.rtm.rtm_type = RTN_UNICAST; > + req.rtm.rtm_dst_len = inet_mask_len(mask); > + rta.rta_dst = &dst; > + rta.rta_oif = &dev->ifindex; > + > + tb = fib_new_table (req.rtm.rtm_table); > + if (tb) > + err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL); > + else > + err = ENOBUFS; > + return err; > +} > + > +static error_t > +delete_static_route(struct device *dev, in_addr_t dst, in_addr_t mask) > +{ > + error_t err; > + struct kern_rta rta; > + struct > + { > + struct nlmsghdr nlh; > + struct rtmsg rtm; > + } req; > + struct fib_table *tb; > + > + if (bad_mask (mask, dst)) > + return EINVAL; > + > + req.nlh.nlmsg_pid = 0; > + req.nlh.nlmsg_seq = 0; > + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); > + > + memset (&req.rtm, 0, sizeof req.rtm); > + memset (&rta, 0, sizeof rta); > + > + /* Delete existing static route on configured device matching src/dst */ > + req.nlh.nlmsg_type = RTM_DELROUTE; > + req.nlh.nlmsg_flags = 0; > + > + req.rtm.rtm_protocol = RTPROT_BOOT; > + req.rtm.rtm_scope = RT_SCOPE_LINK; > + req.rtm.rtm_type = RTN_UNICAST; > + req.rtm.rtm_dst_len = inet_mask_len(mask); > + rta.rta_dst = &dst; > + rta.rta_oif = &dev->ifindex; > + tb = fib_get_table (req.rtm.rtm_table); > + if (tb) > + { > + err = - (*tb->tb_delete) > + (tb, &req.rtm, &rta, &req.nlh, 0); > + if (err && err != ESRCH) > + return err; > + err = 0; > + } > + return err; > +} > + > +error_t > +add_route (struct device *dev, const struct srtentry *r) > +{ > + error_t err; > + > + if (!r) > + return EINVAL; > + > + if (r->rt_flags & RTF_GATEWAY) > + err = add_gateway(dev, r->rt_dest, r->rt_mask, r->rt_gateway); > + else > + err = add_static_route(dev, r->rt_dest, r->rt_mask); > + > + return err; > +} > + > +error_t > +delete_route (struct device *dev, const struct srtentry *r) > +{ > + error_t err; > + > + if (!r) > + return EINVAL; > + > + if (r->rt_flags & RTF_GATEWAY) > + err = delete_gateway(dev, r->rt_dest, r->rt_mask, r->rt_gateway); > + else > + err = delete_static_route(dev, r->rt_dest, r->rt_mask); > + > + return err; > +} > + > enum siocgif_type > { > ADDR, > @@ -158,6 +388,56 @@ siocsifXaddr (struct sock_user *user, > return err; > } > > +/* 10 SIOCADDRT -- Add a network route */ > +kern_return_t > +S_iioctl_siocaddrt (struct sock_user *user, > + const ifname_t ifnam, > + const struct srtentry route) > +{ > + error_t err = 0; > + struct device *dev; > + > + if (!user) > + return EOPNOTSUPP; > + > + dev = get_dev (ifnam); > + > + if (!dev) > + err = ENODEV; > + else if (user->sock->sk->family != AF_INET) > + err = EINVAL; > + else > + err = add_route (dev, &route); > + > + pthread_mutex_unlock (&global_lock); > + return err; > +} > + > +/* 11 SIOCDELRT -- Delete a network route */ > +kern_return_t > +S_iioctl_siocdelrt (struct sock_user *user, > + const ifname_t ifnam, > + const struct srtentry route) > +{ > + error_t err = 0; > + struct device *dev; > + > + if (!user) > + return EOPNOTSUPP; > + > + dev = get_dev (ifnam); > + > + if (!dev) > + err = ENODEV; > + else if (user->sock->sk->family != AF_INET) > + err = EINVAL; > + else > + err = delete_route (dev, &route); > + > + pthread_mutex_unlock (&global_lock); > + return err; > +} > + > /* 12 SIOCSIFADDR -- Set address of a network interface. */ > SIOCSIF (addr, ADDR); > > diff --git a/pfinet/options.c b/pfinet/options.c > index ae44759dc..b945257be 100644 > --- a/pfinet/options.c > +++ b/pfinet/options.c > @@ -28,6 +28,7 @@ > #include <error.h> > #include <netinet/in.h> > #include <arpa/inet.h> > +#include <hurd/ioctl_types.h> > > #include "pfinet.h" > > @@ -60,6 +61,10 @@ extern struct inet6_dev *ipv6_find_idev (struct device > *dev); > extern int inet6_addr_add (int ifindex, struct in6_addr *pfx, int plen); > extern int inet6_addr_del (int ifindex, struct in6_addr *pfx, int plen); > > +/* iioctl.c */ > +extern error_t add_route (struct device *dev, struct srtentry *r); > +extern error_t delete_route (struct device *dev, struct srtentry *r); > + > #ifdef CONFIG_IPV6 > static struct rt6_info * ipv6_get_dflt_router (void); > #endif > @@ -504,65 +509,22 @@ parse_opt (int opt, char *arg, struct argp_state *state) > #endif /* CONFIG_IPV6 */ > } > > - /* Set the default gateway. This code is cobbled together from what > - the SIOCADDRT ioctl code does, and from the apparent functionality > - of the "netlink" layer from perusing a little. */ > + /* Set the default gateway. */ > + > { > - struct kern_rta rta; > - struct > - { > - struct nlmsghdr nlh; > - struct rtmsg rtm; > - } req; > - struct fib_table *tb; > - > - req.nlh.nlmsg_pid = 0; > - req.nlh.nlmsg_seq = 0; > - req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); > - > - memset (&req.rtm, 0, sizeof req.rtm); > - memset (&rta, 0, sizeof rta); > - req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; > - req.rtm.rtm_type = RTN_UNICAST; > - req.rtm.rtm_protocol = RTPROT_STATIC; > - > - if (!gw4_in) > - { > - /* Delete any existing default route on configured devices */ > - for (in = h->interfaces; in < h->interfaces + h->num_interfaces; > - in++) > - { > - req.nlh.nlmsg_type = RTM_DELROUTE; > - req.nlh.nlmsg_flags = 0; > - rta.rta_oif = &in->device->ifindex; > - tb = fib_get_table (req.rtm.rtm_table); > - if (tb) > - { > - err = - (*tb->tb_delete) > - (tb, &req.rtm, &rta, &req.nlh, 0); > - if (err && err != ESRCH) > - { > - pthread_mutex_unlock (&global_lock); > - FAIL (err, 17, 0, > - "cannot remove old default gateway"); > - } > - err = 0; > - } > - } > - } > - else > + struct srtentry route = {0}; > + route.rt_flags = RTF_GATEWAY; > + route.rt_mask = INADDR_ANY; > + route.rt_dest = INADDR_ANY; > + route.rt_gateway = h->curint->gateway; > + > + if (gw4_in) > { > - /* Add a default route, replacing any existing one. */ > - rta.rta_oif = &gw4_in->device->ifindex; > - rta.rta_gw = &gw4_in->gateway; > - req.nlh.nlmsg_type = RTM_NEWROUTE; > - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; > - tb = fib_new_table (req.rtm.rtm_table); > - err = (!tb ? ENOBUFS > - : - (*tb->tb_insert) (tb, &req.rtm, &rta, &req.nlh, 0)); > + /* Add a default route */ > + err = add_route (gw4_in->device, &route); > if (err) > { > - pthread_mutex_unlock (&global_lock); > + pthread_mutex_unlock (&global_lock); > FAIL (err, 17, 0, "cannot set default gateway"); > } > } > @@ -592,55 +554,13 @@ parse_opt (int opt, char *arg, struct argp_state *state) > /* Setup the routing required for DHCP. */ > for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) > { > - struct kern_rta rta; > - struct > - { > - struct nlmsghdr nlh; > - struct rtmsg rtm; > - } req; > - struct fib_table *tb; > - struct rtentry route; > - struct sockaddr_in *dst; > - struct device *dev; > - > if (!in->device) > continue; > + struct srtentry route = {0}; > + route.rt_flags = 0; > + route.rt_dest = INADDR_ANY; > > - dst = (struct sockaddr_in *) &route.rt_dst; > - if (!in->device->name) > - { > - pthread_mutex_unlock (&global_lock); > - FAIL (ENODEV, 17, 0, "unknown device"); > - } > - dev = dev_get (in->device->name); > - if (!dev) > - { > - pthread_mutex_unlock (&global_lock); > - FAIL (ENODEV, 17, 0, "unknown device"); > - } > - > - /* Simulate the SIOCADDRT behavior. */ > - memset (&route, 0, sizeof (struct rtentry)); > - memset (&req.rtm, 0, sizeof req.rtm); > - memset (&rta, 0, sizeof rta); > - req.nlh.nlmsg_type = RTM_NEWROUTE; > - > - /* Append this routing for 0.0.0.0. By this way we can send always > - dhcp messages (e.g dhcp renew). */ > - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE > - | NLM_F_APPEND; > - req.rtm.rtm_protocol = RTPROT_BOOT; > - req.rtm.rtm_scope = RT_SCOPE_LINK; > - req.rtm.rtm_type = RTN_UNICAST; > - rta.rta_dst = &dst->sin_addr.s_addr; > - rta.rta_oif = &dev->ifindex; > - > - tb = fib_new_table (req.rtm.rtm_table); > - if (tb) > - err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL); > - else > - err = ENOBUFS; > - > + err = add_route (in->device, &route); > if (err) > { > pthread_mutex_unlock (&global_lock); > -- > 2.34.1 > > >
-- Samuel --- Pour une évaluation indépendante, transparente et rigoureuse ! Je soutiens la Commission d'Évaluation de l'Inria.