Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2010 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <asm/types.h> /* Needed for 2.4 kernels */
     29 
     30 #include <sys/types.h>
     31 #include <sys/socket.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/param.h>
     34 
     35 #include <linux/netlink.h>
     36 #include <linux/rtnetlink.h>
     37 
     38 /* Support older kernels */
     39 #ifndef IFLA_WIRELESS
     40 # define IFLA_WIRELESS (IFLA_MASTER + 1)
     41 #endif
     42 
     43 #include <errno.h>
     44 #include <ctype.h>
     45 #include <stddef.h>
     46 #include <stdio.h>
     47 #include <stdlib.h>
     48 #include <string.h>
     49 #include <unistd.h>
     50 
     51 #include "config.h"
     52 #include "common.h"
     53 #include "configure.h"
     54 #include "dhcp.h"
     55 #include "net.h"
     56 
     57 static int sock_fd;
     58 static struct sockaddr_nl sock_nl;
     59 
     60 int
     61 if_init(struct interface *iface)
     62 {
     63 	char path[PATH_MAX];
     64 	FILE *fp;
     65 	int n;
     66 
     67 	/* We enable promote_secondaries so that we can do this
     68 	 * add 192.168.1.2/24
     69 	 * add 192.168.1.3/24
     70 	 * del 192.168.1.2/24
     71 	 * and the subnet mask moves onto 192.168.1.3/24
     72 	 * This matches the behaviour of BSD which makes coding dhcpcd
     73 	 * a little easier as there's just one behaviour. */
     74 	snprintf(path, sizeof(path),
     75 	    "/proc/sys/net/ipv4/conf/%s/promote_secondaries",
     76 	    iface->name);
     77 
     78 	fp = fopen(path, "w");
     79 	if (fp == NULL)
     80 		return errno == ENOENT ? 0 : -1;
     81 	n = fprintf(fp, "1");
     82 	fclose(fp);
     83 	return n == -1 ? -1 : 0;
     84 }
     85 
     86 int
     87 if_conf(struct interface *iface)
     88 {
     89 	char path[PATH_MAX], buf[1];
     90 	FILE *fp;
     91 
     92 	/* Some qeth setups require the use of the broadcast flag. */
     93 	snprintf(path, sizeof(path),
     94 	    "/sys/class/net/%s/device/layer2",
     95 	    iface->name);
     96 
     97 	fp = fopen(path, "r");
     98 	if (fp == NULL)
     99 		return errno == ENOENT ? 0 : -1;
    100 	if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] == '0')
    101 		iface->state->options->options |= DHCPCD_BROADCAST;
    102 	fclose(fp);
    103 	return 0;
    104 }
    105 
    106 static int
    107 _open_link_socket(struct sockaddr_nl *nl)
    108 {
    109 	int fd;
    110 
    111 	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
    112 		return -1;
    113 	nl->nl_family = AF_NETLINK;
    114 	if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
    115 		return -1;
    116 	set_cloexec(fd);
    117 	return fd;
    118 }
    119 
    120 int
    121 init_sockets(void)
    122 {
    123 	if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    124 		return -1;
    125 	set_cloexec(socket_afnet);
    126 	sock_fd = _open_link_socket(&sock_nl);
    127 	set_cloexec(sock_fd);
    128 	return sock_fd;
    129 }
    130 
    131 int
    132 open_link_socket(void)
    133 {
    134 	struct sockaddr_nl snl;
    135 
    136 	memset(&snl, 0, sizeof(snl));
    137 	snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
    138 	return _open_link_socket(&snl);
    139 }
    140 
    141 static int
    142 get_netlink(int fd, int flags,
    143     int (*callback)(struct nlmsghdr *))
    144 {
    145 	char *buf = NULL, *nbuf;
    146 	ssize_t buflen = 0, bytes;
    147 	struct nlmsghdr *nlm;
    148 	int r = -1;
    149 
    150 	for (;;) {
    151 		bytes = recv(fd, NULL, 0,
    152 		    flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
    153 		if (bytes == -1) {
    154 			if (errno == EAGAIN) {
    155 				r = 0;
    156 				goto eexit;
    157 			}
    158 			if (errno == EINTR)
    159 				continue;
    160 			goto eexit;
    161 		} else if (bytes == buflen) {
    162 			/* Support kernels older than 2.6.22 */
    163 			if (bytes == 0)
    164 				bytes = 512;
    165 			else
    166 				bytes *= 2;
    167 		}
    168 		if (buflen < bytes) {
    169 			/* Alloc 1 more so we work with older kernels */
    170 			buflen = bytes + 1;
    171 			nbuf = realloc(buf, buflen);
    172 			if (nbuf == NULL)
    173 				goto eexit;
    174 			buf = nbuf;
    175 		}
    176 		bytes = recv(fd, buf, buflen, flags);
    177 		if (bytes == -1) {
    178 			if (errno == EAGAIN) {
    179 				r = 0;
    180 				goto eexit;
    181 			}
    182 			if (errno == EINTR)
    183 				continue;
    184 			goto eexit;
    185 		}
    186 		for (nlm = (struct nlmsghdr *)buf;
    187 		     NLMSG_OK(nlm, (size_t)bytes);
    188 		     nlm = NLMSG_NEXT(nlm, bytes))
    189 		{
    190 			r = callback(nlm);
    191 			if (r != 0)
    192 				goto eexit;
    193 		}
    194 	}
    195 
    196 eexit:
    197 	free(buf);
    198 	return r;
    199 }
    200 
    201 static int
    202 err_netlink(struct nlmsghdr *nlm)
    203 {
    204 	struct nlmsgerr *err;
    205 	int l;
    206 
    207 	if (nlm->nlmsg_type != NLMSG_ERROR)
    208 		return 0;
    209 	l = nlm->nlmsg_len - sizeof(*nlm);
    210 	if ((size_t)l < sizeof(*err)) {
    211 		errno = EBADMSG;
    212 		return -1;
    213 	}
    214 	err = (struct nlmsgerr *)NLMSG_DATA(nlm);
    215 	if (err->error == 0)
    216 		return l;
    217 	errno = -err->error;
    218 	return -1;
    219 }
    220 
    221 static int
    222 link_route(struct nlmsghdr *nlm)
    223 {
    224 	int len, idx, metric;
    225 	struct rtattr *rta;
    226 	struct rtmsg *rtm;
    227 	struct rt rt;
    228 	char ifn[IF_NAMESIZE + 1];
    229 
    230 	if (nlm->nlmsg_type != RTM_DELROUTE)
    231 		return 0;
    232 
    233 	len = nlm->nlmsg_len - sizeof(*nlm);
    234 	if ((size_t)len < sizeof(*rtm)) {
    235 		errno = EBADMSG;
    236 		return -1;
    237 	}
    238 	rtm = NLMSG_DATA(nlm);
    239 	if (rtm->rtm_type != RTN_UNICAST ||
    240 	    rtm->rtm_table != RT_TABLE_MAIN ||
    241 	    rtm->rtm_family != AF_INET ||
    242 	    nlm->nlmsg_pid == (uint32_t)getpid())
    243 		return 1;
    244 	rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
    245 	len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
    246 	rt.iface = NULL;
    247 	rt.dest.s_addr = INADDR_ANY;
    248 	rt.net.s_addr = INADDR_ANY;
    249 	rt.gate.s_addr = INADDR_ANY;
    250 	rt.next = NULL;
    251 	metric = 0;
    252 	while (RTA_OK(rta, len)) {
    253 		switch (rta->rta_type) {
    254 		case RTA_DST:
    255 			memcpy(&rt.dest.s_addr, RTA_DATA(rta),
    256 			    sizeof(rt.dest.s_addr));
    257 			break;
    258 		case RTA_GATEWAY:
    259 			memcpy(&rt.gate.s_addr, RTA_DATA(rta),
    260 			    sizeof(rt.gate.s_addr));
    261 			break;
    262 		case RTA_OIF:
    263 			idx = *(int *)RTA_DATA(rta);
    264 			if (if_indextoname(idx, ifn))
    265 				rt.iface = find_interface(ifn);
    266 			break;
    267 		case RTA_PRIORITY:
    268 			metric = *(int *)RTA_DATA(rta);
    269 			break;
    270 		}
    271 		rta = RTA_NEXT(rta, len);
    272 	}
    273 	if (rt.iface != NULL) {
    274 		if (metric == rt.iface->metric) {
    275 			inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
    276 			route_deleted(&rt);
    277 		}
    278 	}
    279 	return 1;
    280 }
    281 
    282 static int
    283 link_addr(struct nlmsghdr *nlm)
    284 {
    285 	int len;
    286 	struct rtattr *rta;
    287 	struct ifaddrmsg *ifa;
    288 	struct in_addr addr, net, dest;
    289 	char ifn[IF_NAMESIZE + 1];
    290 	struct interface *iface;
    291 
    292 	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
    293 		return 0;
    294 
    295 	len = nlm->nlmsg_len - sizeof(*nlm);
    296 	if ((size_t)len < sizeof(*ifa)) {
    297 		errno = EBADMSG;
    298 		return -1;
    299 	}
    300 	if (nlm->nlmsg_pid == (uint32_t)getpid())
    301 		return 1;
    302 	ifa = NLMSG_DATA(nlm);
    303 	if (if_indextoname(ifa->ifa_index, ifn) == NULL)
    304 		return -1;
    305 	iface = find_interface(ifn);
    306 	if (iface == NULL)
    307 		return 1;
    308 	rta = (struct rtattr *) IFA_RTA(ifa);
    309 	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
    310 	addr.s_addr = dest.s_addr = INADDR_ANY;
    311 	dest.s_addr = INADDR_ANY;
    312 	inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
    313 	while (RTA_OK(rta, len)) {
    314 		switch (rta->rta_type) {
    315 		case IFA_ADDRESS:
    316 			if (iface->flags & IFF_POINTOPOINT) {
    317 				memcpy(&dest.s_addr, RTA_DATA(rta),
    318 				    sizeof(addr.s_addr));
    319 			}
    320 			break;
    321 		case IFA_LOCAL:
    322 			memcpy(&addr.s_addr, RTA_DATA(rta),
    323 			    sizeof(addr.s_addr));
    324 			break;
    325 		}
    326 		rta = RTA_NEXT(rta, len);
    327 	}
    328 	handle_ifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
    329 	return 1;
    330 }
    331 
    332 static int
    333 link_netlink(struct nlmsghdr *nlm)
    334 {
    335 	int len;
    336 	struct rtattr *rta;
    337 	struct ifinfomsg *ifi;
    338 	char ifn[IF_NAMESIZE + 1];
    339 
    340 	len = link_route(nlm);
    341 	if (len != 0)
    342 		return len;
    343 	len = link_addr(nlm);
    344 	if (len != 0)
    345 		return len;
    346 
    347 	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
    348 		return 0;
    349 	len = nlm->nlmsg_len - sizeof(*nlm);
    350 	if ((size_t)len < sizeof(*ifi)) {
    351 		errno = EBADMSG;
    352 		return -1;
    353 	}
    354 	ifi = NLMSG_DATA(nlm);
    355 	if (ifi->ifi_flags & IFF_LOOPBACK)
    356 		return 1;
    357 	rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
    358 	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
    359 	*ifn = '\0';
    360 	while (RTA_OK(rta, len)) {
    361 		switch (rta->rta_type) {
    362 		case IFLA_WIRELESS:
    363 			/* Ignore wireless messages */
    364 			if (nlm->nlmsg_type == RTM_NEWLINK &&
    365 			    ifi->ifi_change == 0)
    366 				return 1;
    367 			break;
    368 		case IFLA_IFNAME:
    369 			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
    370 			break;
    371 		}
    372 		rta = RTA_NEXT(rta, len);
    373 	}
    374 	if (nlm->nlmsg_type == RTM_NEWLINK)
    375 		len = ifi->ifi_change == ~0U ? 1 : 0;
    376 	else
    377 		len = -1;
    378 	handle_interface(len, ifn);
    379 	return 1;
    380 }
    381 
    382 int
    383 manage_link(int fd)
    384 {
    385 	return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
    386 }
    387 
    388 static int
    389 send_netlink(struct nlmsghdr *hdr)
    390 {
    391 	int r;
    392 	struct iovec iov;
    393 	struct msghdr msg;
    394 	static unsigned int seq;
    395 
    396 	memset(&iov, 0, sizeof(iov));
    397 	iov.iov_base = hdr;
    398 	iov.iov_len = hdr->nlmsg_len;
    399 	memset(&msg, 0, sizeof(msg));
    400 	msg.msg_name = &sock_nl;
    401 	msg.msg_namelen = sizeof(sock_nl);
    402 	msg.msg_iov = &iov;
    403 	msg.msg_iovlen = 1;
    404 	/* Request a reply */
    405 	hdr->nlmsg_flags |= NLM_F_ACK;
    406 	hdr->nlmsg_seq = ++seq;
    407 
    408 	if (sendmsg(sock_fd, &msg, 0) != -1)
    409 		r = get_netlink(sock_fd, 0, &err_netlink);
    410 	else
    411 		r = -1;
    412 	return r;
    413 }
    414 
    415 #define NLMSG_TAIL(nmsg)						\
    416 	((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
    417 
    418 static int
    419 add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
    420     const void *data, int alen)
    421 {
    422 	int len = RTA_LENGTH(alen);
    423 	struct rtattr *rta;
    424 
    425 	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
    426 		errno = ENOBUFS;
    427 		return -1;
    428 	}
    429 
    430 	rta = NLMSG_TAIL(n);
    431 	rta->rta_type = type;
    432 	rta->rta_len = len;
    433 	memcpy(RTA_DATA(rta), data, alen);
    434 	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
    435 
    436 	return 0;
    437 }
    438 
    439 static int
    440 add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, uint32_t data)
    441 {
    442 	int len = RTA_LENGTH(sizeof(data));
    443 	struct rtattr *rta;
    444 
    445 	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
    446 		errno = ENOBUFS;
    447 		return -1;
    448 	}
    449 
    450 	rta = NLMSG_TAIL(n);
    451 	rta->rta_type = type;
    452 	rta->rta_len = len;
    453 	memcpy(RTA_DATA(rta), &data, sizeof(data));
    454 	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
    455 
    456 	return 0;
    457 }
    458 
    459 struct nlma
    460 {
    461 	struct nlmsghdr hdr;
    462 	struct ifaddrmsg ifa;
    463 	char buffer[64];
    464 };
    465 
    466 struct nlmr
    467 {
    468 	struct nlmsghdr hdr;
    469 	struct rtmsg rt;
    470 	char buffer[256];
    471 };
    472 
    473 int
    474 if_address(const struct interface *iface,
    475     const struct in_addr *address, const struct in_addr *netmask,
    476     const struct in_addr *broadcast, int action)
    477 {
    478 	struct nlma *nlm;
    479 	int retval = 0;
    480 
    481 	nlm = xzalloc(sizeof(*nlm));
    482 	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
    483 	nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
    484 	if (action >= 0) {
    485 		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
    486 		nlm->hdr.nlmsg_type = RTM_NEWADDR;
    487 	} else
    488 		nlm->hdr.nlmsg_type = RTM_DELADDR;
    489 	if (!(nlm->ifa.ifa_index = if_nametoindex(iface->name))) {
    490 		free(nlm);
    491 		errno = ENODEV;
    492 		return -1;
    493 	}
    494 	nlm->ifa.ifa_family = AF_INET;
    495 	nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
    496 	/* This creates the aliased interface */
    497 	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
    498 	    iface->name, strlen(iface->name) + 1);
    499 	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
    500 	    &address->s_addr, sizeof(address->s_addr));
    501 	if (action >= 0 && broadcast)
    502 		add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
    503 		    &broadcast->s_addr, sizeof(broadcast->s_addr));
    504 
    505 	if (send_netlink(&nlm->hdr) == -1)
    506 		retval = -1;
    507 	free(nlm);
    508 	return retval;
    509 }
    510 
    511 int
    512 if_route(const struct interface *iface,
    513     const struct in_addr *destination, const struct in_addr *netmask,
    514     const struct in_addr *gateway, int metric, int action)
    515 {
    516 	struct nlmr *nlm;
    517 	unsigned int ifindex;
    518 	int retval = 0;
    519 
    520 	if (!(ifindex = if_nametoindex(iface->name))) {
    521 		errno = ENODEV;
    522 		return -1;
    523 	}
    524 
    525 	nlm = xzalloc(sizeof(*nlm));
    526 	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    527 	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
    528 	if (action == 0)
    529 		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
    530 	else if (action == 1)
    531 		nlm->hdr.nlmsg_flags = NLM_F_CREATE /*| NLM_F_EXCL*/;
    532 	else
    533 		nlm->hdr.nlmsg_type = RTM_DELROUTE;
    534 	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
    535 	nlm->rt.rtm_family = AF_INET;
    536 	nlm->rt.rtm_table = RT_TABLE_MAIN;
    537 
    538 	if (action == -1 || action == -2)
    539 		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
    540 	else {
    541 		nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
    542 		/* We only change route metrics for kernel routes */
    543 		if (destination->s_addr ==
    544 		    (iface->addr.s_addr & iface->net.s_addr) &&
    545 		    netmask->s_addr == iface->net.s_addr)
    546 			nlm->rt.rtm_protocol = RTPROT_KERNEL;
    547 		else
    548 			nlm->rt.rtm_protocol = RTPROT_BOOT;
    549 		if (gateway->s_addr == INADDR_ANY ||
    550 		    (gateway->s_addr == destination->s_addr &&
    551 			netmask->s_addr == INADDR_BROADCAST))
    552 			nlm->rt.rtm_scope = RT_SCOPE_LINK;
    553 		else
    554 			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
    555 		nlm->rt.rtm_type = RTN_UNICAST;
    556 	}
    557 
    558 	nlm->rt.rtm_dst_len = inet_ntocidr(*netmask);
    559 	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
    560 	    &destination->s_addr, sizeof(destination->s_addr));
    561 	if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
    562 		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
    563 		    &iface->addr.s_addr, sizeof(iface->addr.s_addr));
    564 	}
    565 	/* If destination == gateway then don't add the gateway */
    566 	if (destination->s_addr != gateway->s_addr ||
    567 	    netmask->s_addr != INADDR_BROADCAST)
    568 		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
    569 		    &gateway->s_addr, sizeof(gateway->s_addr));
    570 
    571 	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
    572 	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, metric);
    573 
    574 	if (send_netlink(&nlm->hdr) == -1)
    575 		retval = -1;
    576 	free(nlm);
    577 	return retval;
    578 }
    579