Skip to content

Commit

Permalink
Merge pull request #3419 from opensourcerouting/freebsd-route-warning…
Browse files Browse the repository at this point in the history
…-fix

zebra: fix some boot up warnings on FreeBSD
  • Loading branch information
donaldsharp committed Dec 6, 2018
2 parents 60e2b4f + c69f2c1 commit 8ba26ec
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 117 deletions.
3 changes: 2 additions & 1 deletion zebra/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,8 @@ void if_get_flags(struct interface *ifp)
strncpy(ifmr.ifm_name, ifp->name, IFNAMSIZ);

/* Seems not all interfaces implement this ioctl */
if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 &&
errno != EINVAL)
flog_err_sys(EC_LIB_SYSTEM_CALL,
"if_ioctl(SIOCGIFMEDIA) failed: %s",
safe_strerror(errno));
Expand Down
270 changes: 154 additions & 116 deletions zebra/kernel_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,18 @@ extern struct zebra_privs_t zserv_privs;
* 0). We follow this practice without questioning it, but it is a
* bug if quagga calls ROUNDUP with 0.
*/
#ifdef __APPLE__
#define ROUNDUP_TYPE int
#else
#define ROUNDUP_TYPE long
#endif

/*
* Because of these varying conventions, the only sane approach is for
* the <net/route.h> header to define some flavor of ROUNDUP macro.
*/

#if defined(SA_SIZE)
/* SAROUNDUP is the only thing we need, and SA_SIZE provides that */
#define SAROUNDUP(a) SA_SIZE(a)
#else /* !SA_SIZE */

/* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */
#if defined(RT_ROUNDUP)
#define ROUNDUP(a) RT_ROUNDUP(a)
#endif /* defined(RT_ROUNDUP) */
Expand All @@ -96,20 +97,17 @@ extern struct zebra_privs_t zserv_privs;
* have it in its headers, this will break rather obviously and you'll
* have to fix it here.
*/

/* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */
#ifdef __APPLE__
#define ROUNDUP_TYPE int
#else
#define ROUNDUP_TYPE long
#endif

#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a)-1) | (sizeof(ROUNDUP_TYPE) - 1))) \
: sizeof(ROUNDUP_TYPE))

#endif /* defined(ROUNDUP) */


#if defined(SA_SIZE)
/* SAROUNDUP is the only thing we need, and SA_SIZE provides that */
#define SAROUNDUP(a) SA_SIZE(a)
#else /* !SA_SIZE */
/*
* Given a pointer (sockaddr or void *), return the number of bytes
* taken up by the sockaddr and any padding needed for alignment.
Expand All @@ -133,60 +131,6 @@ extern struct zebra_privs_t zserv_privs;

#endif /* !SA_SIZE */

/*
* We use a call to an inline function to copy (PNT) to (DEST)
* 1. Calculating the length of the copy requires an #ifdef to determine
* if sa_len is a field and can't be used directly inside a #define
* 2. So the compiler doesn't complain when DEST is NULL, which is only true
* when we are skipping the copy and incrementing to the next SA
*/
static inline void rta_copy(union sockunion *dest, caddr_t src)
{
int len;
if (!dest)
return;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
len = (((struct sockaddr *)src)->sa_len > sizeof(*dest))
? sizeof(*dest)
: ((struct sockaddr *)src)->sa_len;
#else
len = (SAROUNDUP(src) > sizeof(*dest)) ? sizeof(*dest) : SAROUNDUP(src);
#endif
memcpy(dest, src, len);
}

#define RTA_ADDR_GET(DEST, RTA, RTMADDRS, PNT) \
if ((RTMADDRS) & (RTA)) { \
int len = SAROUNDUP((PNT)); \
if (af_check(((struct sockaddr *)(PNT))->sa_family)) \
rta_copy((DEST), (PNT)); \
(PNT) += len; \
}
#define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \
if ((RTMADDRS) & (RTA)) { \
int len = SAROUNDUP((PNT)); \
rta_copy((DEST), (PNT)); \
(PNT) += len; \
}

#define RTA_NAME_GET(DEST, RTA, RTMADDRS, PNT, LEN) \
if ((RTMADDRS) & (RTA)) { \
uint8_t *pdest = (uint8_t *)(DEST); \
int len = SAROUNDUP((PNT)); \
struct sockaddr_dl *sdl = (struct sockaddr_dl *)(PNT); \
if (IS_ZEBRA_DEBUG_KERNEL) \
zlog_debug("%s: RTA_SDL_GET nlen %d, alen %d", \
__func__, sdl->sdl_nlen, sdl->sdl_alen); \
if (((DEST) != NULL) && (sdl->sdl_family == AF_LINK) \
&& (sdl->sdl_nlen < IFNAMSIZ) && (sdl->sdl_nlen <= len)) { \
memcpy(pdest, sdl->sdl_data, sdl->sdl_nlen); \
pdest[sdl->sdl_nlen] = '\0'; \
(LEN) = sdl->sdl_nlen; \
} \
(PNT) += len; \
} else { \
(LEN) = 0; \
}
/* Routing socket message types. */
const struct message rtm_type_str[] = {{RTM_ADD, "RTM_ADD"},
{RTM_DELETE, "RTM_DELETE"},
Expand Down Expand Up @@ -286,6 +230,9 @@ int dplane_routing_sock = -1;
/* Yes I'm checking ugly routing socket behavior. */
/* #define DEBUG */

size_t rta_get(caddr_t sap, void *dest, size_t destlen);
size_t rta_getsdlname(caddr_t sap, void *dest, short *destlen);

/* Supported address family check. */
static inline int af_check(int family)
{
Expand All @@ -296,6 +243,63 @@ static inline int af_check(int family)
return 0;
}

size_t rta_get(caddr_t sap, void *destp, size_t destlen)
{
struct sockaddr *sa = (struct sockaddr *)sap;
uint8_t *dest = destp;
size_t tlen, copylen;

#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
copylen = sa->sa_len;
tlen = (copylen == 0) ? sizeof(ROUNDUP_TYPE) : ROUNDUP(copylen);
#else /* !HAVE_STRUCT_SOCKADDR_SA_LEN */
copylen = tlen = SAROUNDUP(sap);
#endif /* !HAVE_STRUCT_SOCKADDR_SA_LEN */

if (copylen > 0 && dest != NULL && af_check(sa->sa_family)) {
if (copylen > destlen) {
zlog_warn("%s: destination buffer too small (%lu vs %lu)",
__func__, copylen, destlen);
memcpy(dest, sap, destlen);
} else
memcpy(dest, sap, copylen);
}

return tlen;
}

size_t rta_getsdlname(caddr_t sap, void *destp, short *destlen)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sap;
struct sockaddr *sa = (struct sockaddr *)sap;
uint8_t *dest = destp;
size_t tlen, copylen;

copylen = sdl->sdl_nlen;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
tlen = (sa->sa_len == 0) ? sizeof(ROUNDUP_TYPE) : ROUNDUP(sa->sa_len);
#else /* !HAVE_STRUCT_SOCKADDR_SA_LEN */
tlen = SAROUNDUP(sap);
#endif /* !HAVE_STRUCT_SOCKADDR_SA_LEN */

if (copylen > 0 && dest != NULL && sdl->sdl_family == AF_LINK) {
if (copylen > IFNAMSIZ) {
zlog_warn("%s: destination buffer too small (%lu vs %d)",
__func__, copylen, IFNAMSIZ);
memcpy(dest, sdl->sdl_data, IFNAMSIZ);
dest[IFNAMSIZ] = 0;
*destlen = IFNAMSIZ;
} else {
memcpy(dest, sdl->sdl_data, copylen);
dest[copylen] = 0;
*destlen = copylen;
}
} else
*destlen = 0;

return tlen;
}

/* Dump routing table flag for debug purpose. */
static void rtm_flag_dump(int flag)
{
Expand Down Expand Up @@ -408,6 +412,7 @@ int ifm_read(struct if_msghdr *ifm)
struct sockaddr_dl *sdl;
char ifname[IFNAMSIZ];
short ifnlen = 0;
int maskbit;
caddr_t cp;

/* terminate ifname at head (for strnlen) and tail (for safety) */
Expand Down Expand Up @@ -439,21 +444,19 @@ int ifm_read(struct if_msghdr *ifm)
cp = cp + 12;
#endif

RTA_ADDR_GET(NULL, RTA_DST, ifm->ifm_addrs, cp);
RTA_ADDR_GET(NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
RTA_ATTR_GET(NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
RTA_ADDR_GET(NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
sdl = (struct sockaddr_dl *)cp;
RTA_NAME_GET(ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
RTA_ADDR_GET(NULL, RTA_IFA, ifm->ifm_addrs, cp);
RTA_ADDR_GET(NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
RTA_ADDR_GET(NULL, RTA_BRD, ifm->ifm_addrs, cp);
#ifdef RTA_LABEL
RTA_ATTR_GET(NULL, RTA_LABEL, ifm->ifm_addrs, cp);
#endif
#ifdef RTA_SRC
RTA_ADDR_GET(NULL, RTA_SRC, ifm->ifm_addrs, cp);
#endif
/* Look up for RTA_IFP and skip others. */
for (maskbit = 1; maskbit; maskbit <<= 1) {
if ((maskbit & ifm->ifm_addrs) == 0)
continue;
if (maskbit != RTA_IFP) {
cp += rta_get(cp, NULL, 0);
continue;
}

/* Save the pointer to the structure. */
sdl = (struct sockaddr_dl *)cp;
cp += rta_getsdlname(cp, ifname, &ifnlen);
}

if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: sdl ifname %s", __func__,
Expand Down Expand Up @@ -560,7 +563,7 @@ int ifm_read(struct if_msghdr *ifm)
* - Solaris has no sdl_len, but sdl_data[244]
* presumably, it's not going to run past that, so sizeof()
* is fine here.
* a nonzero ifnlen from RTA_NAME_GET() means sdl is valid
* a nonzero ifnlen from rta_getsdlname() means sdl is valid
*/
ifp->ll_type = ZEBRA_LLT_UNKNOWN;
ifp->hw_addr_len = 0;
Expand Down Expand Up @@ -654,6 +657,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr,
caddr_t pnt, end;
union sockunion dst;
union sockunion gateway;
int maskbit;

pnt = (caddr_t)(ifm + 1);
end = ((caddr_t)ifm) + ifm->ifam_msglen;
Expand All @@ -666,20 +670,41 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr,
memset(&gateway, 0, sizeof(union sockunion));

/* We fetch each socket variable into sockunion. */
RTA_ADDR_GET(&dst, RTA_DST, ifm->ifam_addrs, pnt);
RTA_ADDR_GET(&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt);
RTA_ATTR_GET(mask, RTA_NETMASK, ifm->ifam_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_GENMASK, ifm->ifam_addrs, pnt);
RTA_NAME_GET(ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen);
RTA_ADDR_GET(addr, RTA_IFA, ifm->ifam_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt);
RTA_ADDR_GET(brd, RTA_BRD, ifm->ifam_addrs, pnt);
#ifdef RTA_LABEL
RTA_ATTR_GET(NULL, RTA_LABEL, ifm->ifam_addrs, pnt);
#endif
#ifdef RTA_SRC
RTA_ADDR_GET(NULL, RTA_SRC, ifm->ifam_addrs, pnt);
#endif
for (maskbit = 1; maskbit; maskbit <<= 1) {
if ((maskbit & ifm->ifam_addrs) == 0)
continue;

switch (maskbit) {
case RTA_DST:
pnt += rta_get(pnt, &dst, sizeof(dst));
break;
case RTA_GATEWAY:
pnt += rta_get(pnt, &gateway, sizeof(gateway));
break;
case RTA_NETMASK:
pnt += rta_get(pnt, mask, sizeof(*mask));
break;
case RTA_IFP:
pnt += rta_getsdlname(pnt, ifname, ifnlen);
break;
case RTA_IFA:
pnt += rta_get(pnt, addr, sizeof(*addr));
break;
case RTA_BRD:
pnt += rta_get(pnt, brd, sizeof(*brd));
break;

default:
pnt += rta_get(pnt, NULL, 0);
break;
}

if (pnt > end) {
zlog_warn("%s: overflow detected (pnt:%p end:%p)",
__func__, pnt, end);
break;
}
}

if (IS_ZEBRA_DEBUG_KERNEL) {
int family = sockunion_family(addr);
Expand Down Expand Up @@ -714,6 +739,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr,
}

/* Assert read up end point matches to end point */
pnt = (caddr_t)ROUNDUP((size_t)pnt);
if (pnt != end)
zlog_debug("ifam_read() doesn't read all socket data");
}
Expand Down Expand Up @@ -822,6 +848,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest,
char *ifname, short *ifnlen)
{
caddr_t pnt, end;
int maskbit;

/* Pnt points out socket data start point. */
pnt = (caddr_t)(rtm + 1);
Expand All @@ -840,25 +867,36 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest,
memset(mask, 0, sizeof(union sockunion));

/* We fetch each socket variable into sockunion. */
RTA_ADDR_GET(dest, RTA_DST, rtm->rtm_addrs, pnt);
RTA_ADDR_GET(gate, RTA_GATEWAY, rtm->rtm_addrs, pnt);
RTA_ATTR_GET(mask, RTA_NETMASK, rtm->rtm_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_GENMASK, rtm->rtm_addrs, pnt);
RTA_NAME_GET(ifname, RTA_IFP, rtm->rtm_addrs, pnt, *ifnlen);
RTA_ADDR_GET(NULL, RTA_IFA, rtm->rtm_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt);
RTA_ADDR_GET(NULL, RTA_BRD, rtm->rtm_addrs, pnt);
#ifdef RTA_LABEL
#if 0
union sockunion label;
memset(&label, 0, sizeof(label));
RTA_ATTR_GET(&label, RTA_LABEL, rtm->rtm_addrs, pnt);
#endif
RTA_ATTR_GET(NULL, RTA_LABEL, rtm->rtm_addrs, pnt);
#endif
#ifdef RTA_SRC
RTA_ADDR_GET(NULL, RTA_SRC, rtm->rtm_addrs, pnt);
#endif
/* We fetch each socket variable into sockunion. */
for (maskbit = 1; maskbit; maskbit <<= 1) {
if ((maskbit & rtm->rtm_addrs) == 0)
continue;

switch (maskbit) {
case RTA_DST:
pnt += rta_get(pnt, dest, sizeof(*dest));
break;
case RTA_GATEWAY:
pnt += rta_get(pnt, gate, sizeof(*gate));
break;
case RTA_NETMASK:
pnt += rta_get(pnt, mask, sizeof(*mask));
break;
case RTA_IFP:
pnt += rta_getsdlname(pnt, ifname, ifnlen);
break;

default:
pnt += rta_get(pnt, NULL, 0);
break;
}

if (pnt > end) {
zlog_warn("%s: overflow detected (pnt:%p end:%p)",
__func__, pnt, end);
break;
}
}

/* If there is netmask information set it's family same as
destination family*/
Expand Down

0 comments on commit 8ba26ec

Please sign in to comment.