On Sun, Jul 14, 2019 at 05:07:33PM +0300, Vadim Penzin wrote: > Please find below a patch that contains the following: > > (a) An explanation of alignment of address structures within a routing > message; > > (b) An example (I admit, it is somewhat lengthy --- 146 lines) of a basic > parser of route(4) messages. > > (This message is a follow-up to > https://marc.info/?l=openbsd-tech&m=155627978527725) > > Index: route.4 > =================================================================== > RCS file: /cvs/src/share/man/man4/route.4,v > retrieving revision 1.52 > diff -u -p -r1.52 route.4 > --- route.4 30 Apr 2019 16:34:19 -0000 1.52 > +++ route.4 14 Jul 2019 13:39:33 -0000 > @@ -137,13 +137,13 @@ routing information for all address fami > to a specific address family by specifying which one is desired. > There can be more than one routing socket open per system. > .Pp > -Messages are formed by a header followed by a small > +A routing message consists of a header that may be followed by a > number of > .Vt sockaddr > -structures (which are variable length), > -interpreted by position, and delimited > -by the length entry in the > -.Vt sockaddr . > +structures of a variable size (the size of a particular structure > +is determined by its > +.Vt sa_len > +entry; every structure is aligned on the boundary of sizeof(long)). > An example of a message with four addresses might be an > IPv4 route addition: the destination, netmask, gateway, and label, > since both netmasks and labels are sent over the routing socket as > @@ -477,6 +477,119 @@ Specifiers for which addresses are prese > #define RTA_SRC 0x100 /* source sockaddr present */ > #define RTA_SRCMASK 0x200 /* source netmask present */ > #define RTA_LABEL 0x400 /* route label present */ > +.Ed > +.Sh EXAMPLES > +Parsing a routing message. > +.Bd -literal > +#include <sys/socket.h> > +#include <net/if.h> > +#include <net/route.h> > +#include <stdint.h> > +#include <err.h> > + > +/* An abstraction of a routing message. */ > +union rt_msg { > + struct rt_msghdr rt; > + struct if_msghdr ifm; > + struct ifa_msghdr ifa; > + struct if_announcemsghdr ifan; > + uint8_t buf [ RTM_MAXSIZE ]; > +}; > + > +#define rt_msglen rt.rtm_msglen > +#define rt_version rt.rtm_version > +#define rt_type rt.rtm_type > +#define rt_hdrlen rt.rtm_hdrlen > +#define rt_buf buf > + > +/* Round up the size of a struct sockaddr as required by route(4). */ > +#define ROUNDUP(x) (1 + (((x) - 1) | (sizeof(long) - 1))) > + > +/* Parse address structures that may follow the header. */ > + > +static union rt_msg * > +rt_msg_parse_addrs (union rt_msg * const msg, const int addrs) > +{ > + const void *p = (void *) msg + msg->rt_hdrlen; > + const void * const q = (void *) msg + msg->rt_msglen; > + int mask = addrs; > + > + while (p < q && mask ) { > + const struct sockaddr * const sa = p; > + const int rta = mask ^ (mask & mask - 1); > + > + /* > + * Here the variable `sa' points to the current sockadr > + * and the variable `rta' holds the corresponding > + * RTA_ value. > + * > + * NOTE: Before using these variables, you MUST validate > + * that (a) the value of `rta' is defined and expected; > + * (b) `sa_len' of `sa' must correspond to its `sa_family'. > + */ > + > + p += ROUNDUP (sa->sa_len); > + mask &= ~rta; > + } > + > + if (mask) > + warn ("A route(4) message is missing (some) addresses."); > + > + if (p < q) > + warn ("A route(4) message contains odd data."); > + > + if (p > q) { > + err (4, "A route(4) message is malformed."); > + return NULL; > + } > + > + return msg; > +} > + > +/* Parse a message. */ > + > +static union rt_msg * > +rt_msg_parse ( union rt_msg * const msg ) > +{ > + int addrs = 0; > + > + if (msg -> rt_version != RTM_VERSION ) { > + err (4, "Unexpected version of a route(4) message: %d", > + msg->rt_version); > + return NULL; > + } > + > + switch (msg -> rt_type) { > + case RTM_ADD: > + case RTM_DELETE: > + case RTM_CHANGE: > + case RTM_GET: > + case RTM_LOSING: > + case RTM_REDIRECT: > + case RTM_MISS: > + case RTM_RESOLVE: > + case RTM_DESYNC: > + addrs = msg->rt.rtm_addrs; > + break; > + case RTM_NEWADDR: > + case RTM_DELADDR: > + addrs = msg->ifa.ifam_addrs; > + break; > + case RTM_IFINFO: > + addrs = msg->ifm.ifm_addrs; > + break; > + case RTM_IFANNOUNCE: > + return msg; > + case RTM_INVALIDATE: > + err (4, "RTM_INVALIDATE received from route(4)."); > + return NULL; > + default: > + warn ("Unknown route(4) message: %d", msg->rt_type ); > + return NULL; > + } > + > + return rt_msg_parse_addrs (msg, addrs); > +}
I don't like this example. It is not in the style of any rtsock parser we have in tree. rt_msg_parse_addrs() is to complex to easily understand. There are too many blank spots in the example that need to be filled in to make it actully usable. In my opinion doing a proper example would go beyond the scope of the man page. -- :wq Claudio
