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 ,