mirror of
https://github.com/radvd-project/radvd.git
synced 2025-12-20 01:11:37 +08:00
GCC8 added a warning for string truncation that fires on the interface name handling. Use the same fix as found in iproute2 to solve it, replacing `strncpy(dst, src, sz-1)` with `memset(dst, NULL, size)` and then `strlcpy(dst, src, sizeof(dst))`. `strlcpy` ensures NULL terminated strings in all cases where `strncpy` does not. Reference: https://patchwork.ozlabs.org/project/netdev/patch/20180319165638.30166-3-stephen@networkplumber.org/ Reference: https://developers.redhat.com/blog/2018/05/24/detecting-string-truncation-with-gcc-8 Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
222 lines
6.4 KiB
C
222 lines
6.4 KiB
C
/*
|
|
*
|
|
* Authors:
|
|
* Lars Fenneberg <lf@elemental.net>
|
|
*
|
|
* This software is Copyright 1996,1997 by the above mentioned author(s),
|
|
* All Rights Reserved.
|
|
*
|
|
* The license which is distributed with this software in the file COPYRIGHT
|
|
* applies to this software. If your distribution is missing this file, you
|
|
* may request it from <reubenhwk@gmail.com>.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "defaults.h"
|
|
#include "includes.h"
|
|
#include "pathnames.h"
|
|
#include "radvd.h"
|
|
|
|
int check_device(int sock, struct Interface *iface)
|
|
{
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strlcpy(ifr.ifr_name, iface->props.name, sizeof(ifr.ifr_name));
|
|
|
|
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
|
flog(LOG_ERR, "ioctl(SIOCGIFFLAGS) failed on %s: %s", iface->props.name, strerror(errno));
|
|
return -1;
|
|
} else {
|
|
dlog(LOG_ERR, 5, "ioctl(SIOCGIFFLAGS) succeeded on %s", iface->props.name);
|
|
}
|
|
|
|
if (!(ifr.ifr_flags & IFF_UP)) {
|
|
dlog(LOG_ERR, 4, "%s is not up", iface->props.name);
|
|
return -1;
|
|
} else {
|
|
dlog(LOG_ERR, 4, "%s is up", iface->props.name);
|
|
}
|
|
|
|
if (!(ifr.ifr_flags & IFF_RUNNING)) {
|
|
dlog(LOG_ERR, 4, "%s is not running", iface->props.name);
|
|
return -1;
|
|
} else {
|
|
dlog(LOG_ERR, 4, "%s is running", iface->props.name);
|
|
}
|
|
|
|
if (!iface->UnicastOnly &&
|
|
!(ifr.ifr_flags & (IFF_MULTICAST | IFF_POINTOPOINT))) {
|
|
flog(LOG_INFO,
|
|
"%s does not support multicast or point-to-point, forcing UnicastOnly",
|
|
iface->props.name);
|
|
iface->UnicastOnly = 1;
|
|
} else {
|
|
dlog(LOG_ERR, 4, "%s supports multicast or is point-to-point",
|
|
iface->props.name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int get_v4addr(const char *ifn, unsigned int *dst)
|
|
{
|
|
|
|
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (fd < 0) {
|
|
flog(LOG_ERR, "create socket for IPv4 ioctl failed on %s: %s", ifn, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strlcpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
|
|
ifr.ifr_addr.sa_family = AF_INET;
|
|
|
|
if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
|
|
flog(LOG_ERR, "ioctl(SIOCGIFADDR) failed on %s: %s", ifn, strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
struct sockaddr_in *addr = (struct sockaddr_in *)(&ifr.ifr_addr);
|
|
|
|
dlog(LOG_DEBUG, 3, "%s IPv4 address is: %s", ifn, inet_ntoa(addr->sin_addr));
|
|
|
|
*dst = addr->sin_addr.s_addr;
|
|
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmp_iface_addrs(void const *a, void const *b) { return memcmp(a, b, sizeof(struct in6_addr)); }
|
|
|
|
/*
|
|
* Return first IPv6 link local addr in if_addr.
|
|
* Return all the IPv6 addresses in if_addrs in ascending
|
|
* order.
|
|
* Return value is -1 if there was no link local addr.
|
|
* otherwise return value is count of addres in if_addrs
|
|
* not including the all zero (unspecified) addr at the
|
|
* end of the list.
|
|
*/
|
|
int get_iface_addrs(char const *name, struct in6_addr *if_addr, struct in6_addr **if_addrs)
|
|
{
|
|
struct ifaddrs *addresses = 0;
|
|
int link_local_set = 0;
|
|
int i = 0;
|
|
|
|
if (getifaddrs(&addresses) != 0) {
|
|
flog(LOG_ERR, "getifaddrs failed on %s: %s", name, strerror(errno));
|
|
} else {
|
|
for (struct ifaddrs *ifa = addresses; ifa != NULL; ifa = ifa->ifa_next) {
|
|
|
|
if (!ifa->ifa_addr)
|
|
continue;
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
|
continue;
|
|
|
|
struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)ifa->ifa_addr;
|
|
|
|
/* Skip if it is not the interface we're looking for. */
|
|
if (strcmp(ifa->ifa_name, name) != 0)
|
|
continue;
|
|
|
|
*if_addrs = realloc(*if_addrs, (i + 1) * sizeof(struct in6_addr));
|
|
(*if_addrs)[i++] = a6->sin6_addr;
|
|
|
|
/* Skip if it is not a linklocal address or link locak address already found*/
|
|
uint8_t const ll_prefix[] = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
|
|
if (link_local_set || 0 != memcmp(&(a6->sin6_addr), ll_prefix, sizeof(ll_prefix)))
|
|
continue;
|
|
|
|
if (if_addr)
|
|
memcpy(if_addr, &(a6->sin6_addr), sizeof(struct in6_addr));
|
|
|
|
link_local_set = 1;
|
|
}
|
|
}
|
|
|
|
if (addresses)
|
|
freeifaddrs(addresses);
|
|
|
|
/* last item in the list is all zero (unspecified) address */
|
|
*if_addrs = realloc(*if_addrs, (i + 1) * sizeof(struct in6_addr));
|
|
memset(&(*if_addrs)[i], 0, sizeof(struct in6_addr));
|
|
|
|
/* Sort the addresses so the output is predictable. */
|
|
qsort(*if_addrs, i, sizeof(struct in6_addr), cmp_iface_addrs);
|
|
|
|
if (!link_local_set)
|
|
return -1;
|
|
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
* Saves the first link local address seen on the specified interface to iface->if_addr
|
|
* and builds a list of all the other addrs.
|
|
*/
|
|
int setup_iface_addrs(struct Interface *iface)
|
|
{
|
|
int rc = get_iface_addrs(iface->props.name, &iface->props.if_addr, &iface->props.if_addrs);
|
|
|
|
if (-1 != rc) {
|
|
iface->props.addrs_count = rc;
|
|
char addr_str[INET6_ADDRSTRLEN];
|
|
addrtostr(&iface->props.if_addr, addr_str, sizeof(addr_str));
|
|
dlog(LOG_DEBUG, 4, "%s linklocal address: %s", iface->props.name, addr_str);
|
|
for (int i = 0; i < rc; ++i) {
|
|
addrtostr(&iface->props.if_addrs[i], addr_str, sizeof(addr_str));
|
|
dlog(LOG_DEBUG, 4, "%s address: %s", iface->props.name, addr_str);
|
|
}
|
|
/* AdvRASrcAddress: allow operator selection of RA source address */
|
|
if (iface->AdvRASrcAddressList != NULL) {
|
|
iface->props.if_addr_rasrc = NULL;
|
|
for (struct AdvRASrcAddress *current = iface->AdvRASrcAddressList; current; current = current->next) {
|
|
for (int i = 0; i < iface->props.addrs_count; i++) {
|
|
struct in6_addr cmp_addr = iface->props.if_addrs[i];
|
|
if (0 == memcmp(&cmp_addr, ¤t->address, sizeof(struct in6_addr))) {
|
|
addrtostr(&(cmp_addr), addr_str, sizeof(addr_str));
|
|
dlog(LOG_DEBUG, 4, "AdvRASrcAddress selecting: %s", addr_str);
|
|
iface->props.if_addr_rasrc = &iface->props.if_addrs[i];
|
|
break;
|
|
}
|
|
}
|
|
if (NULL != iface->props.if_addr_rasrc)
|
|
break;
|
|
}
|
|
} else {
|
|
/* AdvRASrcAddress default: Just take the first link-local */
|
|
iface->props.if_addr_rasrc = &iface->props.if_addr;
|
|
}
|
|
} else {
|
|
if (iface->IgnoreIfMissing)
|
|
dlog(LOG_DEBUG, 4, "no linklocal address configured on %s", iface->props.name);
|
|
else
|
|
flog(LOG_ERR, "no linklocal address configured on %s", iface->props.name);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int update_device_index(struct Interface *iface)
|
|
{
|
|
int index = if_nametoindex(iface->props.name);
|
|
|
|
if (0 == index) {
|
|
/* Yes, if_nametoindex returns zero on failure. 2014/01/16 */
|
|
flog(LOG_ERR, "%s not found: %s", iface->props.name, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (iface->props.if_index != index) {
|
|
dlog(LOG_DEBUG, 4, "%s if_index changed from %d to %d", iface->props.name, iface->props.if_index, index);
|
|
iface->props.if_index = index;
|
|
}
|
|
|
|
return 0;
|
|
}
|