Annotation of embedaddon/dnsmasq/src/netlink.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
1.1 misho 2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: #ifdef HAVE_LINUX_NETWORK
20:
21: #include <linux/types.h>
22: #include <linux/netlink.h>
23: #include <linux/rtnetlink.h>
24:
25: /* linux 2.6.19 buggers up the headers, patch it up here. */
26: #ifndef IFA_RTA
27: # define IFA_RTA(r) \
28: ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
29:
30: # include <linux/if_addr.h>
31: #endif
32:
33: #ifndef NDA_RTA
34: # define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
35: #endif
36:
37:
38: static struct iovec iov;
39: static u32 netlink_pid;
40:
41: static int nl_async(struct nlmsghdr *h);
42:
43: void netlink_init(void)
44: {
45: struct sockaddr_nl addr;
46: socklen_t slen = sizeof(addr);
47:
48: addr.nl_family = AF_NETLINK;
49: addr.nl_pad = 0;
50: addr.nl_pid = 0; /* autobind */
51: addr.nl_groups = RTMGRP_IPV4_ROUTE;
52: if (option_bool(OPT_CLEVERBIND))
53: addr.nl_groups |= RTMGRP_IPV4_IFADDR;
54: #ifdef HAVE_IPV6
55: addr.nl_groups |= RTMGRP_IPV6_ROUTE;
56: if (option_bool(OPT_CLEVERBIND))
57: addr.nl_groups |= RTMGRP_IPV6_IFADDR;
58: #endif
59: #ifdef HAVE_DHCP6
60: if (daemon->doing_ra || daemon->doing_dhcp6)
61: addr.nl_groups |= RTMGRP_IPV6_IFADDR;
62: #endif
63:
64: /* May not be able to have permission to set multicast groups don't die in that case */
65: if ((daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1)
66: {
67: if (bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
68: {
69: addr.nl_groups = 0;
70: if (errno != EPERM || bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
71: daemon->netlinkfd = -1;
72: }
73: }
74:
75: if (daemon->netlinkfd == -1 ||
76: getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 1)
77: die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
78:
79: /* save pid assigned by bind() and retrieved by getsockname() */
80: netlink_pid = addr.nl_pid;
81:
82: iov.iov_len = 100;
83: iov.iov_base = safe_malloc(iov.iov_len);
84: }
85:
86: static ssize_t netlink_recv(void)
87: {
88: struct msghdr msg;
89: struct sockaddr_nl nladdr;
90: ssize_t rc;
91:
92: while (1)
93: {
94: msg.msg_control = NULL;
95: msg.msg_controllen = 0;
96: msg.msg_name = &nladdr;
97: msg.msg_namelen = sizeof(nladdr);
98: msg.msg_iov = &iov;
99: msg.msg_iovlen = 1;
100: msg.msg_flags = 0;
101:
102: while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
103:
104: /* make buffer big enough */
105: if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
106: {
107: /* Very new Linux kernels return the actual size needed, older ones always return truncated size */
108: if ((size_t)rc == iov.iov_len)
109: {
110: if (expand_buf(&iov, rc + 100))
111: continue;
112: }
113: else
114: expand_buf(&iov, rc);
115: }
116:
117: /* read it for real */
118: msg.msg_flags = 0;
119: while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
120:
121: /* Make sure this is from the kernel */
122: if (rc == -1 || nladdr.nl_pid == 0)
123: break;
124: }
125:
126: /* discard stuff which is truncated at this point (expand_buf() may fail) */
127: if (msg.msg_flags & MSG_TRUNC)
128: {
129: rc = -1;
130: errno = ENOMEM;
131: }
132:
133: return rc;
134: }
135:
136:
137: /* family = AF_UNSPEC finds ARP table entries.
138: family = AF_LOCAL finds MAC addresses. */
139: int iface_enumerate(int family, void *parm, int (*callback)())
140: {
141: struct sockaddr_nl addr;
142: struct nlmsghdr *h;
143: ssize_t len;
144: static unsigned int seq = 0;
145: int callback_ok = 1, newaddr = 0;
146:
147: struct {
148: struct nlmsghdr nlh;
149: struct rtgenmsg g;
150: } req;
151:
152: addr.nl_family = AF_NETLINK;
153: addr.nl_pad = 0;
154: addr.nl_groups = 0;
155: addr.nl_pid = 0; /* address to kernel */
156:
157: again:
158: if (family == AF_UNSPEC)
159: req.nlh.nlmsg_type = RTM_GETNEIGH;
160: else if (family == AF_LOCAL)
161: req.nlh.nlmsg_type = RTM_GETLINK;
162: else
163: req.nlh.nlmsg_type = RTM_GETADDR;
164:
165: req.nlh.nlmsg_len = sizeof(req);
166: req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
167: req.nlh.nlmsg_pid = 0;
168: req.nlh.nlmsg_seq = ++seq;
169: req.g.rtgen_family = family;
170:
171: /* Don't block in recvfrom if send fails */
172: while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
173: (struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());
174:
175: if (len == -1)
176: return 0;
177:
178: while (1)
179: {
180: if ((len = netlink_recv()) == -1)
181: {
182: if (errno == ENOBUFS)
183: {
184: sleep(1);
185: goto again;
186: }
187: return 0;
188: }
189:
190: for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
191: if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
192: {
193: /* May be multicast arriving async */
194: if (nl_async(h))
1.1.1.2 ! misho 195: {
! 196: newaddr = 1;
! 197: enumerate_interfaces(1); /* reset */
! 198: }
1.1 misho 199: }
200: else if (h->nlmsg_type == NLMSG_DONE)
201: {
202: /* handle async new interface address arrivals, these have to be done
203: after we complete as we're not re-entrant */
204: if (newaddr)
1.1.1.2 ! misho 205: newaddress(dnsmasq_time());
1.1 misho 206:
207: return callback_ok;
208: }
209: else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
210: {
211: struct ifaddrmsg *ifa = NLMSG_DATA(h);
212: struct rtattr *rta = IFA_RTA(ifa);
213: unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
214:
215: if (ifa->ifa_family == family)
216: {
217: if (ifa->ifa_family == AF_INET)
218: {
219: struct in_addr netmask, addr, broadcast;
1.1.1.2 ! misho 220: char *label = NULL;
! 221:
1.1 misho 222: netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
223: addr.s_addr = 0;
224: broadcast.s_addr = 0;
225:
226: while (RTA_OK(rta, len1))
227: {
228: if (rta->rta_type == IFA_LOCAL)
229: addr = *((struct in_addr *)(rta+1));
230: else if (rta->rta_type == IFA_BROADCAST)
231: broadcast = *((struct in_addr *)(rta+1));
1.1.1.2 ! misho 232: else if (rta->rta_type == IFA_LABEL)
! 233: label = RTA_DATA(rta);
1.1 misho 234:
235: rta = RTA_NEXT(rta, len1);
236: }
237:
238: if (addr.s_addr && callback_ok)
1.1.1.2 ! misho 239: if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
1.1 misho 240: callback_ok = 0;
241: }
242: #ifdef HAVE_IPV6
243: else if (ifa->ifa_family == AF_INET6)
244: {
245: struct in6_addr *addrp = NULL;
246: u32 valid = 0, preferred = 0;
247: int flags = 0;
248:
249: while (RTA_OK(rta, len1))
250: {
251: if (rta->rta_type == IFA_ADDRESS)
252: addrp = ((struct in6_addr *)(rta+1));
253: else if (rta->rta_type == IFA_CACHEINFO)
254: {
255: struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
256: preferred = ifc->ifa_prefered;
257: valid = ifc->ifa_valid;
258: }
259: rta = RTA_NEXT(rta, len1);
260: }
261:
262: if (ifa->ifa_flags & IFA_F_TENTATIVE)
263: flags |= IFACE_TENTATIVE;
264:
265: if (ifa->ifa_flags & IFA_F_DEPRECATED)
266: flags |= IFACE_DEPRECATED;
267:
1.1.1.2 ! misho 268: if (!(ifa->ifa_flags & IFA_F_TEMPORARY))
! 269: flags |= IFACE_PERMANENT;
! 270:
1.1 misho 271: if (addrp && callback_ok)
272: if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
273: (int)(ifa->ifa_index), flags,
274: (int) preferred, (int)valid, parm)))
275: callback_ok = 0;
276: }
277: #endif
278: }
279: }
280: else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
281: {
282: struct ndmsg *neigh = NLMSG_DATA(h);
283: struct rtattr *rta = NDA_RTA(neigh);
284: unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
285: size_t maclen = 0;
286: char *inaddr = NULL, *mac = NULL;
287:
288: while (RTA_OK(rta, len1))
289: {
290: if (rta->rta_type == NDA_DST)
291: inaddr = (char *)(rta+1);
292: else if (rta->rta_type == NDA_LLADDR)
293: {
294: maclen = rta->rta_len - sizeof(struct rtattr);
295: mac = (char *)(rta+1);
296: }
297:
298: rta = RTA_NEXT(rta, len1);
299: }
300:
301: if (inaddr && mac && callback_ok)
302: if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
303: callback_ok = 0;
304: }
305: #ifdef HAVE_DHCP6
306: else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
307: {
308: struct ifinfomsg *link = NLMSG_DATA(h);
309: struct rtattr *rta = IFLA_RTA(link);
310: unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
311: char *mac = NULL;
312: size_t maclen = 0;
313:
314: while (RTA_OK(rta, len1))
315: {
316: if (rta->rta_type == IFLA_ADDRESS)
317: {
318: maclen = rta->rta_len - sizeof(struct rtattr);
319: mac = (char *)(rta+1);
320: }
321:
322: rta = RTA_NEXT(rta, len1);
323: }
324:
325: if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
326: !((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
327: callback_ok = 0;
328: }
329: #endif
330: }
331: }
332:
333: void netlink_multicast(time_t now)
334: {
335: ssize_t len;
336: struct nlmsghdr *h;
337: int flags, newaddr = 0;
338:
339: /* don't risk blocking reading netlink messages here. */
340: if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
341: fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
342: return;
343:
344: if ((len = netlink_recv()) != -1)
345: for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
346: if (nl_async(h))
347: newaddr = 1;
348:
349: /* restore non-blocking status */
350: fcntl(daemon->netlinkfd, F_SETFL, flags);
351:
352: if (newaddr)
1.1.1.2 ! misho 353: newaddress(now);
1.1 misho 354: }
355:
356: static int nl_async(struct nlmsghdr *h)
357: {
358: if (h->nlmsg_type == NLMSG_ERROR)
359: {
360: struct nlmsgerr *err = NLMSG_DATA(h);
361: if (err->error != 0)
362: my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
363: return 0;
364: }
365: else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
366: {
367: /* We arrange to receive netlink multicast messages whenever the network route is added.
368: If this happens and we still have a DNS packet in the buffer, we re-send it.
369: This helps on DoD links, where frequently the packet which triggers dialling is
370: a DNS query, which then gets lost. By re-sending, we can avoid the lookup
371: failing. */
372: struct rtmsg *rtm = NLMSG_DATA(h);
373:
374: if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
375: {
376: /* Force re-reading resolv file right now, for luck. */
377: daemon->last_resolv = 0;
378:
379: if (daemon->srv_save)
380: {
381: int fd;
382:
383: if (daemon->srv_save->sfd)
384: fd = daemon->srv_save->sfd->fd;
385: else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
386: fd = daemon->rfd_save->fd;
387: else
388: return 0;
389:
390: while(sendto(fd, daemon->packet, daemon->packet_len, 0,
391: &daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
392: }
393: }
394: return 0;
395: }
396: else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
397: return 1; /* clever bind mode - rescan */
398:
399: return 0;
400: }
401: #endif
402:
403:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>