Path: blob/main/tests/sys/net/routing/rtsock_common.h
39604 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2019 Alexander V. Chernikov4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#ifndef _NET_ROUTING_RTSOCK_COMMON_H_28#define _NET_ROUTING_RTSOCK_COMMON_H_2930#include <stdio.h>31#include <stdlib.h>32#include <string.h>33#include <unistd.h>34#include <fcntl.h>35#include <stdbool.h>36#include <ctype.h>37#include <poll.h>3839#include <sys/types.h>40#include <sys/time.h>41#include <sys/param.h>42#include <sys/socket.h>43#include <sys/ioctl.h>44#include <sys/jail.h>45#include <sys/linker.h>46#include <net/if.h>47#include <net/if_dl.h>48#include <net/route.h>4950#include <arpa/inet.h>51#include <net/ethernet.h>5253#include <netinet/in.h>54#include <netinet6/in6_var.h>55#include <netinet6/nd6.h>5657#include <ifaddrs.h>5859#include <errno.h>60#include <err.h>61#include <sysexits.h>6263#include <atf-c.h>64#include "freebsd_test_suite/macros.h"6566#include "rtsock_print.h"67#include "params.h"6869void rtsock_update_rtm_len(struct rt_msghdr *rtm);70void rtsock_validate_message(char *buffer, ssize_t len);71void rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa);7273void file_append_line(char *fname, char *text);7475static int _rtm_seq = 42;767778/*79* Checks if the interface cloner module is present for @name.80*/81static int82_check_cloner(char *name)83{84struct if_clonereq ifcr;85char *cp, *buf;86int idx;87int s;88int found = 0;8990s = socket(AF_LOCAL, SOCK_DGRAM, 0);91if (s == -1)92err(1, "socket(AF_LOCAL,SOCK_DGRAM)");9394memset(&ifcr, 0, sizeof(ifcr));9596if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)97err(1, "SIOCIFGCLONERS for count");9899buf = malloc(ifcr.ifcr_total * IFNAMSIZ);100if (buf == NULL)101err(1, "unable to allocate cloner name buffer");102103ifcr.ifcr_count = ifcr.ifcr_total;104ifcr.ifcr_buffer = buf;105106if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)107err(1, "SIOCIFGCLONERS for names");108109/*110* In case some disappeared in the mean time, clamp it down.111*/112if (ifcr.ifcr_count > ifcr.ifcr_total)113ifcr.ifcr_count = ifcr.ifcr_total;114115for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {116if (!strcmp(cp, name)) {117found = 1;118break;119}120}121122free(buf);123close(s);124125return (found);126}127128static char *129iface_create(char *ifname_orig)130{131struct ifreq ifr;132int s;133char prefix[IFNAMSIZ], ifname[IFNAMSIZ], *result;134135char *src, *dst;136for (src = ifname_orig, dst = prefix; *src && isalpha(*src); src++)137*dst++ = *src;138*dst = '\0';139140memset(&ifr, 0, sizeof(struct ifreq));141142s = socket(AF_LOCAL, SOCK_DGRAM, 0);143strlcpy(ifr.ifr_name, ifname_orig, sizeof(ifr.ifr_name));144145RLOG("creating iface %s %s", prefix, ifr.ifr_name);146if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)147err(1, "SIOCIFCREATE2");148149strlcpy(ifname, ifr.ifr_name, IFNAMSIZ);150RLOG("created interface %s", ifname);151152result = strdup(ifname);153154file_append_line(IFACES_FNAME, ifname);155if (strstr(ifname, "epair") == ifname) {156/* call returned epairXXXa, need to add epairXXXb */157ifname[strlen(ifname) - 1] = 'b';158file_append_line(IFACES_FNAME, ifname);159}160161return (result);162}163164static int165iface_destroy(char *ifname)166{167struct ifreq ifr;168int s;169170s = socket(AF_LOCAL, SOCK_DGRAM, 0);171strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));172173RLOG("destroying interface %s", ifname);174if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)175return (0);176177return (1);178}179180/*181* Open tunneling device such as tuntap and returns fd.182*/183int184iface_open(char *ifname)185{186char path[256];187188snprintf(path, sizeof(path), "/dev/%s", ifname);189190RLOG("opening interface %s", ifname);191int fd = open(path, O_RDWR|O_EXCL);192if (fd == -1) {193RLOG_ERRNO("unable to open interface %s", ifname);194return (-1);195}196197return (fd);198}199200/*201* Sets primary IPv4 addr.202* Returns 0 on success.203*/204static inline int205iface_setup_addr(char *ifname, char *addr, int plen)206{207char cmd[512];208char *af;209210if (strchr(addr, ':'))211af = "inet6";212else213af = "inet";214RLOG("setting af_%s %s/%d on %s", af, addr, plen, ifname);215snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s %s %s/%d", ifname,216af, addr, plen);217218return system(cmd);219}220221/*222* Removes primary IPv4 prefix.223* Returns 0 on success.224*/225static inline int226iface_delete_addr(char *ifname, char *addr)227{228char cmd[512];229230if (strchr(addr, ':')) {231RLOG("removing IPv6 %s from %s", addr, ifname);232snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s inet6 %s delete", ifname, addr);233} else {234RLOG("removing IPv4 %s from %s", addr, ifname);235snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s -alias %s", ifname, addr);236}237238return system(cmd);239}240241int242iface_turn_up(char *ifname)243{244struct ifreq ifr;245int s;246247if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {248RLOG_ERRNO("socket");249return (-1);250}251memset(&ifr, 0, sizeof(struct ifreq));252strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));253if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {254RLOG_ERRNO("ioctl(SIOCGIFFLAGS)");255return (-1);256}257/* Update flags */258if ((ifr.ifr_flags & IFF_UP) == 0) {259ifr.ifr_flags |= IFF_UP;260if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {261RLOG_ERRNO("ioctl(SIOSGIFFLAGS)");262return (-1);263}264RLOG("turned interface %s up", ifname);265}266267return (0);268}269270/*271* Removes ND6_IFF_IFDISABLED from IPv6 interface flags.272* Returns 0 on success.273*/274int275iface_enable_ipv6(char *ifname)276{277struct in6_ndireq nd;278int s;279280if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {281err(1, "socket");282}283memset(&nd, 0, sizeof(nd));284strlcpy(nd.ifname, ifname, sizeof(nd.ifname));285if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {286RLOG_ERRNO("ioctl(SIOCGIFINFO_IN6)");287return (-1);288}289/* Update flags */290if ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0) {291nd.ndi.flags &= ~ND6_IFF_IFDISABLED;292if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {293RLOG_ERRNO("ioctl(SIOCSIFINFO_IN6)");294return (-1);295}296RLOG("enabled IPv6 for %s", ifname);297}298299return (0);300}301302void303file_append_line(char *fname, char *text)304{305FILE *f;306307f = fopen(fname, "a");308fputs(text, f);309fputs("\n", f);310fclose(f);311}312313static int314vnet_wait_interface(char *vnet_name, char *ifname)315{316char buf[512], cmd[512], *line, *token;317FILE *fp;318int i;319320snprintf(cmd, sizeof(cmd), "/usr/sbin/jexec %s /sbin/ifconfig -l", vnet_name);321for (int i = 0; i < 50; i++) {322fp = popen(cmd, "r");323line = fgets(buf, sizeof(buf), fp);324/* cut last\n */325if (line[0])326line[strlen(line)-1] = '\0';327while ((token = strsep(&line, " ")) != NULL) {328if (strcmp(token, ifname) == 0)329return (1);330}331332/* sleep 100ms */333usleep(1000 * 100);334}335336return (0);337}338339void340vnet_switch(char *vnet_name, char **ifnames, int count)341{342char buf[512], cmd[512], *line;343FILE *fp;344int jid, len, ret;345346RLOG("switching to vnet %s with interface(s) %s", vnet_name, ifnames[0]);347len = snprintf(cmd, sizeof(cmd),348"/usr/sbin/jail -i -c name=%s persist vnet", vnet_name);349for (int i = 0; i < count && len < sizeof(cmd); i++) {350len += snprintf(&cmd[len], sizeof(cmd) - len,351" vnet.interface=%s", ifnames[i]);352}353RLOG("jail cmd: \"%s\"\n", cmd);354355fp = popen(cmd, "r");356if (fp == NULL)357atf_tc_fail("jail creation failed");358line = fgets(buf, sizeof(buf), fp);359if (line == NULL)360atf_tc_fail("empty output from jail(8)");361jid = strtol(line, NULL, 10);362if (jid <= 0) {363atf_tc_fail("invalid jail output: %s", line);364}365366RLOG("created jail jid=%d", jid);367file_append_line(JAILS_FNAME, vnet_name);368369/* Wait while interface appearsh inside vnet */370for (int i = 0; i < count; i++) {371if (vnet_wait_interface(vnet_name, ifnames[i]))372continue;373atf_tc_fail("unable to move interface %s to jail %s",374ifnames[i], vnet_name);375}376377if (jail_attach(jid) == -1) {378RLOG_ERRNO("jail %s attach failed: ret=%d", vnet_name, errno);379atf_tc_fail("jail attach failed");380}381382RLOG("attached to the jail");383}384385void386vnet_switch_one(char *vnet_name, char *ifname)387{388char *ifnames[1];389390ifnames[0] = ifname;391vnet_switch(vnet_name, ifnames, 1);392}393394395#define SA_F_IGNORE_IFNAME 0x01396#define SA_F_IGNORE_IFTYPE 0x02397#define SA_F_IGNORE_MEMCMP 0x04398int399sa_equal_msg_flags(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz, int flags)400{401char a_s[64], b_s[64];402const struct sockaddr_in *a4, *b4;403const struct sockaddr_in6 *a6, *b6;404const struct sockaddr_dl *al, *bl;405406if (a == NULL) {407snprintf(msg, sz, "first sa is NULL");408return 0;409}410if (b == NULL) {411snprintf(msg, sz, "second sa is NULL");412return 0;413}414415if (a->sa_family != b->sa_family) {416snprintf(msg, sz, "family: %d vs %d", a->sa_family, b->sa_family);417return 0;418}419if (a->sa_len != b->sa_len) {420snprintf(msg, sz, "len: %d vs %d", a->sa_len, b->sa_len);421return 0;422}423424switch (a->sa_family) {425case AF_INET:426a4 = (const struct sockaddr_in *)a;427b4 = (const struct sockaddr_in *)b;428if (a4->sin_addr.s_addr != b4->sin_addr.s_addr) {429inet_ntop(AF_INET, &a4->sin_addr, a_s, sizeof(a_s));430inet_ntop(AF_INET, &b4->sin_addr, b_s, sizeof(b_s));431snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);432return 0;433}434if (a4->sin_port != b4->sin_port) {435snprintf(msg, sz, "port diff: %d vs %d",436ntohs(a4->sin_port), ntohs(b4->sin_port));437//return 0;438}439const uint32_t *a32, *b32;440a32 = (const uint32_t *)a4->sin_zero;441b32 = (const uint32_t *)b4->sin_zero;442if ((*a32 != *b32) || (*(a32 + 1) != *(b32 + 1))) {443snprintf(msg, sz, "zero diff: 0x%08X%08X vs 0x%08X%08X",444ntohl(*a32), ntohl(*(a32 + 1)),445ntohl(*b32), ntohl(*(b32 + 1)));446return 0;447}448return 1;449case AF_INET6:450a6 = (const struct sockaddr_in6 *)a;451b6 = (const struct sockaddr_in6 *)b;452if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr)) {453inet_ntop(AF_INET6, &a6->sin6_addr, a_s, sizeof(a_s));454inet_ntop(AF_INET6, &b6->sin6_addr, b_s, sizeof(b_s));455snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);456return 0;457}458if (a6->sin6_scope_id != b6->sin6_scope_id) {459snprintf(msg, sz, "scope diff: %u vs %u", a6->sin6_scope_id, b6->sin6_scope_id);460return 0;461}462break;463case AF_LINK:464al = (const struct sockaddr_dl *)a;465bl = (const struct sockaddr_dl *)b;466467if (al->sdl_index != bl->sdl_index) {468snprintf(msg, sz, "sdl_index diff: %u vs %u", al->sdl_index, bl->sdl_index);469return 0;470}471472if ((al->sdl_alen != bl->sdl_alen) || (memcmp(LLADDR(al), LLADDR(bl), al->sdl_alen) != 0)) {473char abuf[64], bbuf[64];474sa_print_hd(abuf, sizeof(abuf), LLADDR(al), al->sdl_alen);475sa_print_hd(bbuf, sizeof(bbuf), LLADDR(bl), bl->sdl_alen);476snprintf(msg, sz, "sdl_alen diff: {%s} (%d) vs {%s} (%d)",477abuf, al->sdl_alen, bbuf, bl->sdl_alen);478return 0;479}480481if (((flags & SA_F_IGNORE_IFTYPE) == 0) && (al->sdl_type != bl->sdl_type)) {482snprintf(msg, sz, "sdl_type diff: %u vs %u", al->sdl_type, bl->sdl_type);483return 0;484}485486if (((flags & SA_F_IGNORE_IFNAME) == 0) && ((al->sdl_nlen != bl->sdl_nlen) ||487(memcmp(al->sdl_data, bl->sdl_data, al->sdl_nlen) != 0))) {488char abuf[64], bbuf[64];489memcpy(abuf, al->sdl_data, al->sdl_nlen);490abuf[al->sdl_nlen] = '\0';491memcpy(bbuf, bl->sdl_data, bl->sdl_nlen);492abuf[bl->sdl_nlen] = '\0';493snprintf(msg, sz, "sdl_nlen diff: {%s} (%d) vs {%s} (%d)",494abuf, al->sdl_nlen, bbuf, bl->sdl_nlen);495return 0;496}497498if (flags & SA_F_IGNORE_MEMCMP)499return 1;500break;501}502503if (memcmp(a, b, a->sa_len)) {504int i;505for (i = 0; i < a->sa_len; i++)506if (((const char *)a)[i] != ((const char *)b)[i])507break;508509sa_print(a, 1);510sa_print(b, 1);511512snprintf(msg, sz, "overall memcmp() reports diff for af %d offset %d",513a->sa_family, i);514return 0;515}516return 1;517}518519int520sa_equal_msg(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz)521{522523return sa_equal_msg_flags(a, b, msg, sz, 0);524}525526void527sa_fill_mask4(struct sockaddr_in *sin, int plen)528{529530memset(sin, 0, sizeof(struct sockaddr_in));531sin->sin_family = AF_INET;532sin->sin_len = sizeof(struct sockaddr_in);533sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);534}535536void537sa_fill_mask6(struct sockaddr_in6 *sin6, uint8_t mask)538{539uint32_t *cp;540541memset(sin6, 0, sizeof(struct sockaddr_in6));542sin6->sin6_family = AF_INET6;543sin6->sin6_len = sizeof(struct sockaddr_in6);544545for (cp = (uint32_t *)&sin6->sin6_addr; mask >= 32; mask -= 32)546*cp++ = 0xFFFFFFFF;547if (mask > 0)548*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);549}550551/* 52:54:00:14:e3:10 */552#define ETHER_MAC_MAX_LENGTH 17553554int555sa_convert_str_to_sa(const char *_addr, struct sockaddr *sa)556{557int error;558559int af = AF_UNSPEC;560561char *addr = strdup(_addr);562int retcode = 0;563564/* classify AF by str */565if (strchr(addr, ':')) {566/* inet6 or ether */567char *k;568int delim_cnt = 0;569for (k = addr; *k; k++)570if (*k == ':')571delim_cnt++;572af = AF_INET6;573574if (delim_cnt == 5) {575k = strchr(addr, '%');576if (k != NULL && (k - addr) <= ETHER_MAC_MAX_LENGTH)577af = AF_LINK;578}579} else if (strchr(addr, '.'))580af = AF_INET;581582/* */583char *delimiter;584int ifindex = 0;585char *ifname = NULL;586if ((delimiter = strchr(addr, '%')) != NULL) {587*delimiter = '\0';588ifname = delimiter + 1;589ifindex = if_nametoindex(ifname);590if (ifindex == 0)591RLOG("unable to find ifindex for '%s'", ifname);592else593RLOG("if %s mapped to %d", ifname, ifindex);594}595596if (af == AF_INET6) {597struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;598memset(sin6, 0, sizeof(struct sockaddr_in6));599sin6->sin6_family = AF_INET6;600sin6->sin6_len = sizeof(struct sockaddr_in6);601sin6->sin6_scope_id = ifindex;602error = inet_pton(AF_INET6, addr, &sin6->sin6_addr);603if (error != 1)604RLOG_ERRNO("inet_ntop() failed: ret=%d", error);605else606retcode = 1;607} else if (af == AF_INET) {608struct sockaddr_in *sin = (struct sockaddr_in *)sa;609memset(sin, 0, sizeof(struct sockaddr_in));610sin->sin_family = AF_INET;611sin->sin_len = sizeof(struct sockaddr_in);612error = inet_pton(AF_INET, addr, &sin->sin_addr);613if (error != 1)614RLOG("inet_ntop() failed: ret=%d", error);615else616retcode = 1;617} else if (af == AF_LINK) {618struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;619memset(sdl, 0, sizeof(struct sockaddr_dl));620sdl->sdl_family = AF_LINK;621sdl->sdl_len = sizeof(struct sockaddr_dl);622sdl->sdl_index = ifindex;623sdl->sdl_alen = 6;624struct ether_addr *ea = (struct ether_addr *)LLADDR(sdl);625if (ether_aton_r(addr, ea) == NULL)626RLOG("ether_aton() failed");627else628retcode = 1;629}630631return (retcode);632}633634635int636rtsock_setup_socket()637{638int fd;639int af = AF_UNSPEC; /* 0 to capture messages from all AFs */640fd = socket(PF_ROUTE, SOCK_RAW, af);641642ATF_REQUIRE_MSG(fd != -1, "rtsock open failed: %s", strerror(errno));643644/* Listen for our messages */645int on = 1;646if (setsockopt(fd, SOL_SOCKET,SO_USELOOPBACK, &on, sizeof(on)) < 0)647RLOG_ERRNO("setsockopt failed");648649return (fd);650}651652ssize_t653rtsock_send_rtm(int fd, struct rt_msghdr *rtm)654{655int my_errno;656ssize_t len;657658rtsock_update_rtm_len(rtm);659660len = write(fd, rtm, rtm->rtm_msglen);661my_errno = errno;662RTSOCK_ATF_REQUIRE_MSG(rtm, len == rtm->rtm_msglen,663"rtsock write failed: want %d got %zd (%s)",664rtm->rtm_msglen, len, strerror(my_errno));665666return (len);667}668669struct rt_msghdr *670rtsock_read_rtm(int fd, char *buffer, size_t buflen)671{672ssize_t len;673struct pollfd pfd;674int poll_delay = 5 * 1000; /* 5 seconds */675676/* Check for the data available to read first */677memset(&pfd, 0, sizeof(pfd));678pfd.fd = fd;679pfd.events = POLLIN;680681if (poll(&pfd, 1, poll_delay) == 0)682ATF_REQUIRE_MSG(1 == 0, "rtsock read timed out (%d seconds passed)",683poll_delay / 1000);684685len = read(fd, buffer, buflen);686int my_errno = errno;687ATF_REQUIRE_MSG(len > 0, "rtsock read failed: %s", strerror(my_errno));688689rtsock_validate_message(buffer, len);690return ((struct rt_msghdr *)buffer);691}692693struct rt_msghdr *694rtsock_read_rtm_reply(int fd, char *buffer, size_t buflen, int seq)695{696struct rt_msghdr *rtm;697int found = 0;698699while (true) {700rtm = rtsock_read_rtm(fd, buffer, buflen);701if (rtm->rtm_pid == getpid() && rtm->rtm_seq == seq)702found = 1;703if (found)704RLOG("--- MATCHED RTSOCK MESSAGE ---");705else706RLOG("--- SKIPPED RTSOCK MESSAGE ---");707rtsock_print_rtm(rtm);708if (found)709return (rtm);710}711712/* NOTREACHED */713}714715void716rtsock_prepare_route_message_base(struct rt_msghdr *rtm, int cmd)717{718719memset(rtm, 0, sizeof(struct rt_msghdr));720rtm->rtm_type = cmd;721rtm->rtm_version = RTM_VERSION;722rtm->rtm_seq = _rtm_seq++;723}724725void726rtsock_prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,727struct sockaddr *mask, struct sockaddr *gw)728{729730rtsock_prepare_route_message_base(rtm, cmd);731if (dst != NULL)732rtsock_add_rtm_sa(rtm, RTA_DST, dst);733734if (gw != NULL) {735rtsock_add_rtm_sa(rtm, RTA_GATEWAY, gw);736rtm->rtm_flags |= RTF_GATEWAY;737}738739if (mask != NULL)740rtsock_add_rtm_sa(rtm, RTA_NETMASK, mask);741}742743void744rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa)745{746char *ptr = (char *)(rtm + 1);747for (int i = 0; i < RTAX_MAX; i++) {748if (rtm->rtm_addrs & (1 << i)) {749/* add */750ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);751}752}753754rtm->rtm_addrs |= addr_type;755memcpy(ptr, sa, sa->sa_len);756}757758struct sockaddr *759rtsock_find_rtm_sa(struct rt_msghdr *rtm, int addr_type)760{761char *ptr = (char *)(rtm + 1);762for (int i = 0; i < RTAX_MAX; i++) {763if (rtm->rtm_addrs & (1 << i)) {764if (addr_type == (1 << i))765return ((struct sockaddr *)ptr);766/* add */767ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);768}769}770771return (NULL);772}773774size_t775rtsock_calc_rtm_len(struct rt_msghdr *rtm)776{777size_t len = sizeof(struct rt_msghdr);778779char *ptr = (char *)(rtm + 1);780for (int i = 0; i < RTAX_MAX; i++) {781if (rtm->rtm_addrs & (1 << i)) {782/* add */783int sa_len = ALIGN(((struct sockaddr *)ptr)->sa_len);784len += sa_len;785ptr += sa_len;786}787}788789return len;790}791792void793rtsock_update_rtm_len(struct rt_msghdr *rtm)794{795796rtm->rtm_msglen = rtsock_calc_rtm_len(rtm);797}798799static void800_validate_message_sockaddrs(char *buffer, int rtm_len, size_t offset, int rtm_addrs)801{802struct sockaddr *sa;803size_t parsed_len = offset;804805/* Offset denotes initial header size */806sa = (struct sockaddr *)(buffer + offset);807808for (int i = 0; i < RTAX_MAX; i++) {809if ((rtm_addrs & (1 << i)) == 0)810continue;811parsed_len += SA_SIZE(sa);812RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len <= rtm_len,813"SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, rtm_len);814if (sa->sa_family == AF_LINK) {815struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;816int data_len = sdl->sdl_nlen + sdl->sdl_alen;817data_len += offsetof(struct sockaddr_dl, sdl_data);818819RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer,820data_len <= rtm_len,821"AF_LINK data size exceeds total len: %u vs %u, nlen=%d alen=%d",822data_len, rtm_len, sdl->sdl_nlen, sdl->sdl_alen);823}824sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));825}826}827828/*829* Raises error if base syntax checks fails.830*/831void832rtsock_validate_message(char *buffer, ssize_t len)833{834struct rt_msghdr *rtm;835836ATF_REQUIRE_MSG(len > 0, "read() return %zd, error: %s", len, strerror(errno));837838rtm = (struct rt_msghdr *)buffer;839ATF_REQUIRE_MSG(rtm->rtm_version == RTM_VERSION, "unknown RTM_VERSION: expected %d got %d",840RTM_VERSION, rtm->rtm_version);841ATF_REQUIRE_MSG(rtm->rtm_msglen <= len, "wrong message length: expected %d got %d",842(int)len, (int)rtm->rtm_msglen);843844switch (rtm->rtm_type) {845case RTM_GET:846case RTM_ADD:847case RTM_DELETE:848case RTM_CHANGE:849_validate_message_sockaddrs(buffer, rtm->rtm_msglen,850sizeof(struct rt_msghdr), rtm->rtm_addrs);851break;852case RTM_DELADDR:853case RTM_NEWADDR:854_validate_message_sockaddrs(buffer, rtm->rtm_msglen,855sizeof(struct ifa_msghdr), ((struct ifa_msghdr *)buffer)->ifam_addrs);856break;857}858}859860void861rtsock_validate_pid_ours(struct rt_msghdr *rtm)862{863RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == getpid(), "expected pid %d, got %d",864getpid(), rtm->rtm_pid);865}866867void868rtsock_validate_pid_user(struct rt_msghdr *rtm)869{870RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid, got %d",871rtm->rtm_pid);872}873874void875rtsock_validate_pid_kernel(struct rt_msghdr *rtm)876{877RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == 0, "expected zero pid, got %d",878rtm->rtm_pid);879}880881#endif882883884