Annotation of embedaddon/dnsmasq/src/netlink.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* dnsmasq is Copyright (c) 2000-2016 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:
1.1.1.3 ! misho 41: static void nl_async(struct nlmsghdr *h);
1.1 misho 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;
1.1.1.3 ! misho 145: int callback_ok = 1;
1.1 misho 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 */
1.1.1.3 ! misho 172: while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
! 173: (struct sockaddr *)&addr, sizeof(addr))));
! 174:
! 175: if (errno != 0)
1.1 misho 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 */
1.1.1.3 ! misho 194: nl_async(h);
1.1 misho 195: }
196: else if (h->nlmsg_type == NLMSG_DONE)
1.1.1.3 ! misho 197: return callback_ok;
1.1 misho 198: else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
199: {
200: struct ifaddrmsg *ifa = NLMSG_DATA(h);
201: struct rtattr *rta = IFA_RTA(ifa);
202: unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
203:
204: if (ifa->ifa_family == family)
205: {
206: if (ifa->ifa_family == AF_INET)
207: {
208: struct in_addr netmask, addr, broadcast;
1.1.1.2 misho 209: char *label = NULL;
210:
1.1.1.3 ! misho 211: netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
! 212:
1.1 misho 213: addr.s_addr = 0;
214: broadcast.s_addr = 0;
215:
216: while (RTA_OK(rta, len1))
217: {
218: if (rta->rta_type == IFA_LOCAL)
219: addr = *((struct in_addr *)(rta+1));
220: else if (rta->rta_type == IFA_BROADCAST)
221: broadcast = *((struct in_addr *)(rta+1));
1.1.1.2 misho 222: else if (rta->rta_type == IFA_LABEL)
223: label = RTA_DATA(rta);
1.1 misho 224:
225: rta = RTA_NEXT(rta, len1);
226: }
227:
228: if (addr.s_addr && callback_ok)
1.1.1.2 misho 229: if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
1.1 misho 230: callback_ok = 0;
231: }
232: #ifdef HAVE_IPV6
233: else if (ifa->ifa_family == AF_INET6)
234: {
235: struct in6_addr *addrp = NULL;
236: u32 valid = 0, preferred = 0;
237: int flags = 0;
238:
239: while (RTA_OK(rta, len1))
240: {
241: if (rta->rta_type == IFA_ADDRESS)
242: addrp = ((struct in6_addr *)(rta+1));
243: else if (rta->rta_type == IFA_CACHEINFO)
244: {
245: struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
246: preferred = ifc->ifa_prefered;
247: valid = ifc->ifa_valid;
248: }
249: rta = RTA_NEXT(rta, len1);
250: }
251:
252: if (ifa->ifa_flags & IFA_F_TENTATIVE)
253: flags |= IFACE_TENTATIVE;
254:
255: if (ifa->ifa_flags & IFA_F_DEPRECATED)
256: flags |= IFACE_DEPRECATED;
257:
1.1.1.2 misho 258: if (!(ifa->ifa_flags & IFA_F_TEMPORARY))
259: flags |= IFACE_PERMANENT;
260:
1.1 misho 261: if (addrp && callback_ok)
262: if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
263: (int)(ifa->ifa_index), flags,
264: (int) preferred, (int)valid, parm)))
265: callback_ok = 0;
266: }
267: #endif
268: }
269: }
270: else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
271: {
272: struct ndmsg *neigh = NLMSG_DATA(h);
273: struct rtattr *rta = NDA_RTA(neigh);
274: unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
275: size_t maclen = 0;
276: char *inaddr = NULL, *mac = NULL;
277:
278: while (RTA_OK(rta, len1))
279: {
280: if (rta->rta_type == NDA_DST)
281: inaddr = (char *)(rta+1);
282: else if (rta->rta_type == NDA_LLADDR)
283: {
284: maclen = rta->rta_len - sizeof(struct rtattr);
285: mac = (char *)(rta+1);
286: }
287:
288: rta = RTA_NEXT(rta, len1);
289: }
290:
1.1.1.3 ! misho 291: if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
! 292: inaddr && mac && callback_ok)
1.1 misho 293: if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
294: callback_ok = 0;
295: }
296: #ifdef HAVE_DHCP6
297: else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
298: {
299: struct ifinfomsg *link = NLMSG_DATA(h);
300: struct rtattr *rta = IFLA_RTA(link);
301: unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
302: char *mac = NULL;
303: size_t maclen = 0;
304:
305: while (RTA_OK(rta, len1))
306: {
307: if (rta->rta_type == IFLA_ADDRESS)
308: {
309: maclen = rta->rta_len - sizeof(struct rtattr);
310: mac = (char *)(rta+1);
311: }
312:
313: rta = RTA_NEXT(rta, len1);
314: }
315:
316: if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
317: !((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
318: callback_ok = 0;
319: }
320: #endif
321: }
322: }
323:
1.1.1.3 ! misho 324: void netlink_multicast(void)
1.1 misho 325: {
326: ssize_t len;
327: struct nlmsghdr *h;
1.1.1.3 ! misho 328: int flags;
1.1 misho 329:
330: /* don't risk blocking reading netlink messages here. */
331: if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
332: fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
333: return;
334:
335: if ((len = netlink_recv()) != -1)
336: for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
1.1.1.3 ! misho 337: nl_async(h);
1.1 misho 338:
339: /* restore non-blocking status */
340: fcntl(daemon->netlinkfd, F_SETFL, flags);
341: }
342:
1.1.1.3 ! misho 343: static void nl_async(struct nlmsghdr *h)
1.1 misho 344: {
345: if (h->nlmsg_type == NLMSG_ERROR)
346: {
347: struct nlmsgerr *err = NLMSG_DATA(h);
348: if (err->error != 0)
349: my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
350: }
351: else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
352: {
353: /* We arrange to receive netlink multicast messages whenever the network route is added.
354: If this happens and we still have a DNS packet in the buffer, we re-send it.
355: This helps on DoD links, where frequently the packet which triggers dialling is
356: a DNS query, which then gets lost. By re-sending, we can avoid the lookup
357: failing. */
358: struct rtmsg *rtm = NLMSG_DATA(h);
359:
360: if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
1.1.1.3 ! misho 361: queue_event(EVENT_NEWROUTE);
1.1 misho 362: }
363: else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
1.1.1.3 ! misho 364: queue_event(EVENT_NEWADDR);
1.1 misho 365: }
366: #endif
367:
368:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>