• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * dhcpcd - DHCP client daemon
3   * Copyright (c) 2006-2010 Roy Marples <roy@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
if_init(struct interface * iface)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
if_conf(struct interface * iface)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
_open_link_socket(struct sockaddr_nl * nl)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
init_sockets(void)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
open_link_socket(void)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
get_netlink(int fd,int flags,int (* callback)(struct nlmsghdr *))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
err_netlink(struct nlmsghdr * nlm)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
link_route(struct nlmsghdr * nlm)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
link_addr(struct nlmsghdr * nlm)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
link_netlink(struct nlmsghdr * nlm)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
manage_link(int fd)383  manage_link(int fd)
384  {
385  	return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
386  }
387  
388  static int
send_netlink(struct nlmsghdr * hdr)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
add_attr_l(struct nlmsghdr * n,unsigned int maxlen,int type,const void * data,int alen)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
add_attr_32(struct nlmsghdr * n,unsigned int maxlen,int type,uint32_t data)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
if_address(const struct interface * iface,const struct in_addr * address,const struct in_addr * netmask,const struct in_addr * broadcast,int action)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
if_route(const struct interface * iface,const struct in_addr * destination,const struct in_addr * netmask,const struct in_addr * gateway,int metric,int action)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