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);
+}
 .Ed
 .Sh SEE ALSO
 .Xr netstat 1 ,

Reply via email to