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>
497 lines
13 KiB
C
497 lines
13 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 "netlink.h"
|
|
#include "pathnames.h"
|
|
#include "radvd.h"
|
|
|
|
#ifndef IPV6_ADDR_LINKLOCAL
|
|
#define IPV6_ADDR_LINKLOCAL 0x0020U
|
|
#endif
|
|
|
|
#ifndef ARPHRD_6LOWPAN
|
|
#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */
|
|
#endif
|
|
|
|
static char const *hwstr(unsigned short sa_family);
|
|
uint32_t get_interface_linkmtu(const char *);
|
|
|
|
/*
|
|
* this function gets the hardware type and address of an interface,
|
|
* determines the link layer token length and checks it against
|
|
* the defined prefixes
|
|
*/
|
|
int update_device_info(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, SIOCGIFMTU, &ifr) < 0) {
|
|
flog(LOG_ERR, "ioctl(SIOCGIFMTU) failed on %s: %s", iface->props.name, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
iface->sllao.if_maxmtu = ifr.ifr_mtu;
|
|
dlog(LOG_DEBUG, 3, "%s mtu: %d", iface->props.name, ifr.ifr_mtu);
|
|
|
|
/* RFC 2460: 5. Packet Size Issues */
|
|
/* Get the smallest MTU between the SIOCGIFMTU value and the protocol MTU
|
|
* /proc/sys/net/ipv6/conf/eth0/mtu
|
|
* Because the protocol MTU _may_ be different than the physical link MTU
|
|
*
|
|
* If Link-layer MTU <= 1280: use 1280 (enforced by iface->AdvRAMTU)
|
|
* If Link-layer MTU > 1280: use the lower of:
|
|
* - RA MTU
|
|
* - link-layer MTU
|
|
* - per-protocol MTU
|
|
*/
|
|
iface->props.max_ra_option_size = iface->AdvRAMTU;
|
|
iface->props.max_ra_option_size = MIN(iface->props.max_ra_option_size, MAX(iface->sllao.if_maxmtu, RFC2460_MIN_MTU));
|
|
iface->props.max_ra_option_size =
|
|
MIN(iface->props.max_ra_option_size, MAX(get_interface_linkmtu(iface->props.name), RFC2460_MIN_MTU));
|
|
|
|
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
|
|
flog(LOG_ERR, "ioctl(SIOCGIFHWADDR) failed on %s: %s", iface->props.name, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
dlog(LOG_DEBUG, 3, "%s hardware type: %s", iface->props.name, hwstr(ifr.ifr_hwaddr.sa_family));
|
|
|
|
switch (ifr.ifr_hwaddr.sa_family) {
|
|
case ARPHRD_ETHER:
|
|
iface->sllao.if_hwaddr_len = 48;
|
|
iface->sllao.if_prefix_len = 64;
|
|
char hwaddr[3 * 6];
|
|
sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)ifr.ifr_hwaddr.sa_data[0],
|
|
(unsigned char)ifr.ifr_hwaddr.sa_data[1], (unsigned char)ifr.ifr_hwaddr.sa_data[2],
|
|
(unsigned char)ifr.ifr_hwaddr.sa_data[3], (unsigned char)ifr.ifr_hwaddr.sa_data[4],
|
|
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
|
|
dlog(LOG_DEBUG, 3, "%s hardware address: %s", iface->props.name, hwaddr);
|
|
iface->props.max_ra_option_size -= 14; /* RFC 2464 */
|
|
break;
|
|
#ifdef ARPHRD_FDDI
|
|
case ARPHRD_FDDI:
|
|
iface->sllao.if_hwaddr_len = 48;
|
|
iface->sllao.if_prefix_len = 64;
|
|
iface->props.max_ra_option_size -= 22; /* RFC 2109 */
|
|
break;
|
|
#endif /* ARPHDR_FDDI */
|
|
#ifdef ARPHRD_ARCNET
|
|
case ARPHRD_ARCNET:
|
|
iface->sllao.if_hwaddr_len = 8;
|
|
iface->sllao.if_prefix_len = -1;
|
|
iface->sllao.if_maxmtu = -1;
|
|
/* RFC1201: fragmentation handled at a lower layer.
|
|
* native packet size is 256-512 bytes */
|
|
iface->props.max_ra_option_size -= 0;
|
|
break;
|
|
#endif /* ARPHDR_ARCNET */
|
|
case ARPHRD_6LOWPAN:
|
|
#ifdef HAVE_NETLINK
|
|
/* hwaddr length differs on some L2 type lets detect them */
|
|
iface->sllao.if_hwaddr_len = netlink_get_device_addr_len(iface);
|
|
if (iface->sllao.if_hwaddr_len != -1) {
|
|
iface->sllao.if_hwaddr_len *= 8;
|
|
iface->sllao.if_prefix_len = 64;
|
|
} else {
|
|
iface->sllao.if_prefix_len = -1;
|
|
}
|
|
#else
|
|
iface->sllao.if_hwaddr_len = -1;
|
|
iface->sllao.if_prefix_len = -1;
|
|
#endif
|
|
/* RFC4944: fragmentation handled at a lower layer.
|
|
* native packet size maxes at 127 bytes */
|
|
iface->props.max_ra_option_size -= 0;
|
|
break;
|
|
default:
|
|
iface->sllao.if_hwaddr_len = -1;
|
|
iface->sllao.if_prefix_len = -1;
|
|
iface->sllao.if_maxmtu = -1;
|
|
/* Assume fragmentation handled at a lower layer. */
|
|
iface->props.max_ra_option_size -= 0;
|
|
break;
|
|
}
|
|
|
|
dlog(LOG_DEBUG, 3, "%s link layer token length: %d", iface->props.name, iface->sllao.if_hwaddr_len);
|
|
|
|
dlog(LOG_DEBUG, 3, "%s prefix length: %d", iface->props.name, iface->sllao.if_prefix_len);
|
|
|
|
if (iface->sllao.if_hwaddr_len != -1) {
|
|
unsigned int if_hwaddr_len_bytes = (iface->sllao.if_hwaddr_len + 7) >> 3;
|
|
|
|
if (if_hwaddr_len_bytes > sizeof(iface->sllao.if_hwaddr)) {
|
|
flog(LOG_ERR, "%s address length too big: %d", iface->props.name, if_hwaddr_len_bytes);
|
|
return -2;
|
|
}
|
|
memcpy(iface->sllao.if_hwaddr, ifr.ifr_hwaddr.sa_data, if_hwaddr_len_bytes);
|
|
|
|
char zero[sizeof(iface->props.if_addr)];
|
|
memset(zero, 0, sizeof(zero));
|
|
if (!memcmp(iface->sllao.if_hwaddr, zero, if_hwaddr_len_bytes))
|
|
flog(LOG_WARNING, "WARNING, MAC address on %s is all zero!", iface->props.name);
|
|
}
|
|
|
|
struct AdvPrefix *prefix = iface->AdvPrefixList;
|
|
while (prefix) {
|
|
if ((iface->sllao.if_prefix_len != -1) && (iface->sllao.if_prefix_len != prefix->PrefixLen)) {
|
|
flog(LOG_WARNING, "%s prefix length should be: %d", iface->props.name, iface->sllao.if_prefix_len);
|
|
}
|
|
|
|
prefix = prefix->next;
|
|
}
|
|
|
|
// Regardless of link-layer, every RA message will have an IPV6 header & RA header
|
|
iface->props.max_ra_option_size -= sizeof(struct ip6_hdr);
|
|
iface->props.max_ra_option_size -= sizeof(struct nd_router_advert);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setup_allrouters_membership(int sock, struct Interface *iface)
|
|
{
|
|
struct ipv6_mreq mreq;
|
|
|
|
memset(&mreq, 0, sizeof(mreq));
|
|
mreq.ipv6mr_interface = iface->props.if_index;
|
|
|
|
/* ipv6-allrouters: ff02::2 */
|
|
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xFF020000);
|
|
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2);
|
|
|
|
if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
|
|
/* linux-2.6.12-bk4 returns error with HUP signal but keep listening */
|
|
if (errno != EADDRINUSE) {
|
|
flog(LOG_ERR, "can't join ipv6-allrouters on %s", iface->props.name);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cleanup_allrouters_membership(int sock, struct Interface *iface)
|
|
{
|
|
struct ipv6_mreq mreq;
|
|
|
|
memset(&mreq, 0, sizeof(mreq));
|
|
mreq.ipv6mr_interface = iface->props.if_index;
|
|
|
|
/* ipv6-allrouters: ff02::2 */
|
|
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xFF020000);
|
|
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2);
|
|
|
|
setsockopt(sock, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t get_interface_linkmtu(const char *iface)
|
|
{
|
|
int value;
|
|
FILE *fp = NULL;
|
|
char proc_path[sizeof(PROC_SYS_IP6_LINKMTU) + IFNAMSIZ];
|
|
|
|
snprintf(proc_path, sizeof(PROC_SYS_IP6_LINKMTU) + IFNAMSIZ, PROC_SYS_IP6_LINKMTU, iface);
|
|
|
|
fp = fopen(proc_path, "r");
|
|
if (fp) {
|
|
int rc = fscanf(fp, "%d", &value);
|
|
if (rc != 1) {
|
|
flog(LOG_ERR, "cannot read value from %s: %s", proc_path, strerror(errno));
|
|
exit(1);
|
|
}
|
|
fclose(fp);
|
|
} else {
|
|
flog(LOG_DEBUG, "Correct IPv6 MTU entry not found, "
|
|
"perhaps the procfs is disabled, "
|
|
"or the kernel interface has changed?");
|
|
value = 1280; /* RFC2460: section 5 */
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
int set_interface_linkmtu(const char *iface, uint32_t mtu) { return privsep_interface_linkmtu(iface, mtu); }
|
|
|
|
int set_interface_curhlim(const char *iface, uint8_t hlim) { return privsep_interface_curhlim(iface, hlim); }
|
|
|
|
int set_interface_reachtime(const char *iface, uint32_t rtime) { return privsep_interface_reachtime(iface, rtime); }
|
|
|
|
int set_interface_retranstimer(const char *iface, uint32_t rettimer) { return privsep_interface_retranstimer(iface, rettimer); }
|
|
|
|
int check_ip6_iface_forwarding(const char *iface)
|
|
{
|
|
int value = -1;
|
|
FILE *fp = NULL;
|
|
char path[sizeof(PROC_SYS_IP6_IFACE_FORWARDING) + IFNAMSIZ];
|
|
|
|
snprintf(path, sizeof(PROC_SYS_IP6_IFACE_FORWARDING) + IFNAMSIZ, PROC_SYS_IP6_IFACE_FORWARDING, iface);
|
|
|
|
fp = fopen(path, "r");
|
|
if (fp) {
|
|
int rc = fscanf(fp, "%d", &value);
|
|
if (rc != 1) {
|
|
flog(LOG_ERR, "cannot read value from %s: %s", path, strerror(errno));
|
|
exit(1);
|
|
}
|
|
fclose(fp);
|
|
} else {
|
|
flog(LOG_DEBUG, "Correct IPv6 forwarding procfs entry for interface "
|
|
"not found, perhaps the procfs is disabled, "
|
|
"or the kernel interface has changed?");
|
|
value = -1;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
int check_ip6_forwarding(void)
|
|
{
|
|
int value;
|
|
FILE *fp = NULL;
|
|
|
|
fp = fopen(PROC_SYS_IP6_FORWARDING, "r");
|
|
if (fp) {
|
|
int rc = fscanf(fp, "%d", &value);
|
|
if (rc != 1) {
|
|
flog(LOG_ERR, "cannot read value from %s: %s", PROC_SYS_IP6_FORWARDING, strerror(errno));
|
|
exit(1);
|
|
}
|
|
fclose(fp);
|
|
} else {
|
|
flog(LOG_DEBUG, "Correct IPv6 forwarding procfs entry not found, "
|
|
"perhaps the procfs is disabled, "
|
|
"or the kernel interface has changed?");
|
|
value = -1;
|
|
}
|
|
|
|
#ifdef HAVE_SYSCTL
|
|
int forw_sysctl[] = {SYSCTL_IP6_FORWARDING};
|
|
size_t size = sizeof(value);
|
|
if (!fp && sysctl(forw_sysctl, sizeof(forw_sysctl) / sizeof(forw_sysctl[0]), &value, &size, NULL, 0) < 0) {
|
|
flog(LOG_DEBUG, "Correct IPv6 forwarding sysctl branch not found, "
|
|
"perhaps the kernel interface has changed?");
|
|
return 0; /* this is of advisory value only */
|
|
}
|
|
#endif
|
|
|
|
/* Linux allows the forwarding value to be either 1 or 2.
|
|
* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/ip-sysctl.txt?id=ae8abfa00efb8ec550f772cbd1e1854977d06212#n1078
|
|
*
|
|
* The value 2 indicates forwarding is enabled and that *AS* *WELL* router solicitations are being done.
|
|
*
|
|
* Which is sometimes used on routers performing RS on their WAN (ppp, etc.) links
|
|
*/
|
|
static int warned = 0;
|
|
if (!warned && value != 1 && value != 2) {
|
|
warned = 1;
|
|
flog(LOG_DEBUG, "IPv6 forwarding setting is: %u, should be 1 or 2", value);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static char const *hwstr(unsigned short sa_family)
|
|
{
|
|
char const *rc = 0;
|
|
|
|
switch (sa_family) {
|
|
case ARPHRD_NETROM:
|
|
rc = "ARPHRD_NETROM";
|
|
break;
|
|
case ARPHRD_ETHER:
|
|
rc = "ARPHRD_ETHER";
|
|
break;
|
|
case ARPHRD_EETHER:
|
|
rc = "ARPHRD_EETHER";
|
|
break;
|
|
case ARPHRD_AX25:
|
|
rc = "ARPHRD_AX25";
|
|
break;
|
|
case ARPHRD_PRONET:
|
|
rc = "ARPHRD_PRONET";
|
|
break;
|
|
case ARPHRD_CHAOS:
|
|
rc = "ARPHRD_CHAOS";
|
|
break;
|
|
case ARPHRD_IEEE802:
|
|
rc = "ARPHRD_IEEE802";
|
|
break;
|
|
case ARPHRD_APPLETLK:
|
|
rc = "ARPHRD_APPLETLK";
|
|
break;
|
|
case ARPHRD_DLCI:
|
|
rc = "ARPHRD_DLCI";
|
|
break;
|
|
case ARPHRD_ATM:
|
|
rc = "ARPHRD_ATM";
|
|
break;
|
|
case ARPHRD_METRICOM:
|
|
rc = "ARPHRD_METRICOM";
|
|
break;
|
|
case ARPHRD_IEEE1394:
|
|
rc = "ARPHRD_IEEE1394";
|
|
break;
|
|
case ARPHRD_EUI64:
|
|
rc = "ARPHRD_EUI64";
|
|
break;
|
|
case ARPHRD_INFINIBAND:
|
|
rc = "ARPHRD_INFINIBAND";
|
|
break;
|
|
case ARPHRD_SLIP:
|
|
rc = "ARPHRD_SLIP";
|
|
break;
|
|
case ARPHRD_CSLIP:
|
|
rc = "ARPHRD_CSLIP";
|
|
break;
|
|
case ARPHRD_SLIP6:
|
|
rc = "ARPHRD_SLIP6";
|
|
break;
|
|
case ARPHRD_CSLIP6:
|
|
rc = "ARPHRD_CSLIP6";
|
|
break;
|
|
case ARPHRD_RSRVD:
|
|
rc = "ARPHRD_RSRVD";
|
|
break;
|
|
case ARPHRD_ADAPT:
|
|
return "ARPHRD_ADAPT";
|
|
break;
|
|
case ARPHRD_ROSE:
|
|
rc = "ARPHRD_ROSE";
|
|
break;
|
|
case ARPHRD_X25:
|
|
rc = "ARPHRD_X25";
|
|
break;
|
|
case ARPHRD_HWX25:
|
|
rc = "ARPHRD_HWX25";
|
|
break;
|
|
case ARPHRD_PPP:
|
|
rc = "ARPHRD_PPP";
|
|
break;
|
|
case ARPHRD_CISCO:
|
|
rc = "ARPHRD_CISCO";
|
|
break;
|
|
case ARPHRD_LAPB:
|
|
rc = "ARPHRD_LAPB";
|
|
break;
|
|
case ARPHRD_DDCMP:
|
|
rc = "ARPHRD_DDCMP";
|
|
break;
|
|
case ARPHRD_RAWHDLC:
|
|
rc = "ARPHRD_RAWHDLC";
|
|
break;
|
|
case ARPHRD_TUNNEL:
|
|
rc = "ARPHRD_TUNNEL";
|
|
break;
|
|
case ARPHRD_TUNNEL6:
|
|
rc = "ARPHRD_TUNNEL6";
|
|
break;
|
|
case ARPHRD_FRAD:
|
|
rc = "ARPHRD_FRAD";
|
|
break;
|
|
case ARPHRD_SKIP:
|
|
rc = "ARPHRD_SKIP";
|
|
break;
|
|
case ARPHRD_LOOPBACK:
|
|
rc = "ARPHRD_LOOPBACK";
|
|
break;
|
|
case ARPHRD_LOCALTLK:
|
|
rc = "ARPHRD_LOCALTLK";
|
|
break;
|
|
case ARPHRD_BIF:
|
|
rc = "ARPHRD_BIF";
|
|
break;
|
|
case ARPHRD_SIT:
|
|
rc = "ARPHRD_SIT";
|
|
break;
|
|
case ARPHRD_IPDDP:
|
|
rc = "ARPHRD_IPDDP";
|
|
break;
|
|
case ARPHRD_IPGRE:
|
|
rc = "ARPHRD_IPGRE";
|
|
break;
|
|
case ARPHRD_PIMREG:
|
|
rc = "ARPHRD_PIMREG";
|
|
break;
|
|
case ARPHRD_HIPPI:
|
|
rc = "ARPHRD_HIPPI";
|
|
break;
|
|
case ARPHRD_ASH:
|
|
rc = "ARPHRD_ASH";
|
|
break;
|
|
case ARPHRD_ECONET:
|
|
rc = "ARPHRD_ECONET";
|
|
break;
|
|
case ARPHRD_IRDA:
|
|
rc = "ARPHRD_IRDA";
|
|
break;
|
|
case ARPHRD_FCPP:
|
|
rc = "ARPHRD_FCPP";
|
|
break;
|
|
case ARPHRD_FCAL:
|
|
rc = "ARPHRD_FCAL";
|
|
break;
|
|
case ARPHRD_FCPL:
|
|
rc = "ARPHRD_FCPL";
|
|
break;
|
|
case ARPHRD_FCFABRIC:
|
|
rc = "ARPHRD_FCFABRIC";
|
|
break;
|
|
case ARPHRD_IEEE802_TR:
|
|
rc = "ARPHRD_IEEE802_TR";
|
|
break;
|
|
case ARPHRD_IEEE80211:
|
|
rc = "ARPHRD_IEEE80211";
|
|
break;
|
|
case ARPHRD_IEEE80211_PRISM:
|
|
rc = "ARPHRD_IEEE80211_PRISM";
|
|
break;
|
|
case ARPHRD_IEEE80211_RADIOTAP:
|
|
rc = "ARPHRD_IEEE80211_RADIOTAP";
|
|
break;
|
|
case ARPHRD_IEEE802154:
|
|
rc = "ARPHRD_IEEE802154";
|
|
break;
|
|
#if ARPHRD_IEEE802154_MONITOR
|
|
case ARPHRD_IEEE802154_MONITOR:
|
|
rc = "ARPHRD_IEEE802154_MONITOR";
|
|
break;
|
|
#elif ARPHRD_IEEE802154_PHY
|
|
case ARPHRD_IEEE802154_PHY:
|
|
rc = "ARPHRD_IEEE802154_PHY";
|
|
break;
|
|
#endif
|
|
case ARPHRD_6LOWPAN:
|
|
rc = "ARPHRD_6LOWPAN";
|
|
break;
|
|
case ARPHRD_VOID:
|
|
rc = "ARPHRD_VOID";
|
|
break;
|
|
case ARPHRD_NONE:
|
|
rc = "ARPHRD_NONE";
|
|
break;
|
|
default:
|
|
rc = "unknown";
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|