1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
|
/*
*
* 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;
}
|