]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/netlink.c
1 /* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
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.
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.
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/>.
19 #ifdef HAVE_LINUX_NETWORK
21 #include <linux/types.h>
22 #include <linux/netlink.h>
23 #include <linux/rtnetlink.h>
25 /* linux 2.6.19 buggers up the headers, patch it up here. */
28 ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
30 # include <linux/if_addr.h>
34 # define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
38 static struct iovec iov
;
39 static u32 netlink_pid
;
41 static int nl_async(struct nlmsghdr
*h
);
43 void netlink_init(void)
45 struct sockaddr_nl addr
;
46 socklen_t slen
= sizeof(addr
);
48 addr
.nl_family
= AF_NETLINK
;
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
;
55 addr
.nl_groups
|= RTMGRP_IPV6_ROUTE
;
56 if (option_bool(OPT_CLEVERBIND
))
57 addr
.nl_groups
|= RTMGRP_IPV6_IFADDR
;
60 if (daemon
->doing_ra
|| daemon
->doing_dhcp6
)
61 addr
.nl_groups
|= RTMGRP_IPV6_IFADDR
;
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)
67 if (bind(daemon
->netlinkfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1)
70 if (errno
!= EPERM
|| bind(daemon
->netlinkfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1)
71 daemon
->netlinkfd
= -1;
75 if (daemon
->netlinkfd
== -1 ||
76 getsockname(daemon
->netlinkfd
, (struct sockaddr
*)&addr
, &slen
) == 1)
77 die(_("cannot create netlink socket: %s"), NULL
, EC_MISC
);
79 /* save pid assigned by bind() and retrieved by getsockname() */
80 netlink_pid
= addr
.nl_pid
;
83 iov
.iov_base
= safe_malloc(iov
.iov_len
);
86 static ssize_t
netlink_recv(void)
89 struct sockaddr_nl nladdr
;
94 msg
.msg_control
= NULL
;
95 msg
.msg_controllen
= 0;
96 msg
.msg_name
= &nladdr
;
97 msg
.msg_namelen
= sizeof(nladdr
);
102 while ((rc
= recvmsg(daemon
->netlinkfd
, &msg
, MSG_PEEK
| MSG_TRUNC
)) == -1 && errno
== EINTR
);
104 /* make buffer big enough */
105 if (rc
!= -1 && (msg
.msg_flags
& MSG_TRUNC
))
107 /* Very new Linux kernels return the actual size needed, older ones always return truncated size */
108 if ((size_t)rc
== iov
.iov_len
)
110 if (expand_buf(&iov
, rc
+ 100))
114 expand_buf(&iov
, rc
);
117 /* read it for real */
119 while ((rc
= recvmsg(daemon
->netlinkfd
, &msg
, 0)) == -1 && errno
== EINTR
);
121 /* Make sure this is from the kernel */
122 if (rc
== -1 || nladdr
.nl_pid
== 0)
126 /* discard stuff which is truncated at this point (expand_buf() may fail) */
127 if (msg
.msg_flags
& MSG_TRUNC
)
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
)())
141 struct sockaddr_nl addr
;
144 static unsigned int seq
= 0;
145 int callback_ok
= 1, newaddr
= 0;
152 addr
.nl_family
= AF_NETLINK
;
155 addr
.nl_pid
= 0; /* address to kernel */
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
;
163 req
.nlh
.nlmsg_type
= RTM_GETADDR
;
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
;
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());
180 if ((len
= netlink_recv()) == -1)
182 if (errno
== ENOBUFS
)
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
)
193 /* May be multicast arriving async */
197 enumerate_interfaces(1); /* reset */
200 else if (h
->nlmsg_type
== NLMSG_DONE
)
202 /* handle async new interface address arrivals, these have to be done
203 after we complete as we're not re-entrant */
205 newaddress(dnsmasq_time());
209 else if (h
->nlmsg_type
== RTM_NEWADDR
&& family
!= AF_UNSPEC
&& family
!= AF_LOCAL
)
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
));
215 if (ifa
->ifa_family
== family
)
217 if (ifa
->ifa_family
== AF_INET
)
219 struct in_addr netmask
, addr
, broadcast
;
222 netmask
.s_addr
= htonl(0xffffffff << (32 - ifa
->ifa_prefixlen
));
224 broadcast
.s_addr
= 0;
226 while (RTA_OK(rta
, len1
))
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));
232 else if (rta
->rta_type
== IFA_LABEL
)
233 label
= RTA_DATA(rta
);
235 rta
= RTA_NEXT(rta
, len1
);
238 if (addr
.s_addr
&& callback_ok
)
239 if (!((*callback
)(addr
, ifa
->ifa_index
, label
, netmask
, broadcast
, parm
)))
243 else if (ifa
->ifa_family
== AF_INET6
)
245 struct in6_addr
*addrp
= NULL
;
246 u32 valid
= 0, preferred
= 0;
249 while (RTA_OK(rta
, len1
))
251 if (rta
->rta_type
== IFA_ADDRESS
)
252 addrp
= ((struct in6_addr
*)(rta
+1));
253 else if (rta
->rta_type
== IFA_CACHEINFO
)
255 struct ifa_cacheinfo
*ifc
= (struct ifa_cacheinfo
*)(rta
+1);
256 preferred
= ifc
->ifa_prefered
;
257 valid
= ifc
->ifa_valid
;
259 rta
= RTA_NEXT(rta
, len1
);
262 if (ifa
->ifa_flags
& IFA_F_TENTATIVE
)
263 flags
|= IFACE_TENTATIVE
;
265 if (ifa
->ifa_flags
& IFA_F_DEPRECATED
)
266 flags
|= IFACE_DEPRECATED
;
268 if (!(ifa
->ifa_flags
& IFA_F_TEMPORARY
))
269 flags
|= IFACE_PERMANENT
;
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
)))
280 else if (h
->nlmsg_type
== RTM_NEWNEIGH
&& family
== AF_UNSPEC
)
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
));
286 char *inaddr
= NULL
, *mac
= NULL
;
288 while (RTA_OK(rta
, len1
))
290 if (rta
->rta_type
== NDA_DST
)
291 inaddr
= (char *)(rta
+1);
292 else if (rta
->rta_type
== NDA_LLADDR
)
294 maclen
= rta
->rta_len
- sizeof(struct rtattr
);
295 mac
= (char *)(rta
+1);
298 rta
= RTA_NEXT(rta
, len1
);
301 if (inaddr
&& mac
&& callback_ok
)
302 if (!((*callback
)(neigh
->ndm_family
, inaddr
, mac
, maclen
, parm
)))
306 else if (h
->nlmsg_type
== RTM_NEWLINK
&& family
== AF_LOCAL
)
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
));
314 while (RTA_OK(rta
, len1
))
316 if (rta
->rta_type
== IFLA_ADDRESS
)
318 maclen
= rta
->rta_len
- sizeof(struct rtattr
);
319 mac
= (char *)(rta
+1);
322 rta
= RTA_NEXT(rta
, len1
);
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
)))
333 void netlink_multicast(time_t now
)
337 int flags
, newaddr
= 0;
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)
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
))
349 /* restore non-blocking status */
350 fcntl(daemon
->netlinkfd
, F_SETFL
, flags
);
356 static int nl_async(struct nlmsghdr
*h
)
358 if (h
->nlmsg_type
== NLMSG_ERROR
)
360 struct nlmsgerr
*err
= NLMSG_DATA(h
);
362 my_syslog(LOG_ERR
, _("netlink returns error: %s"), strerror(-(err
->error
)));
365 else if (h
->nlmsg_pid
== 0 && h
->nlmsg_type
== RTM_NEWROUTE
)
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
372 struct rtmsg
*rtm
= NLMSG_DATA(h
);
374 if (rtm
->rtm_type
== RTN_UNICAST
&& rtm
->rtm_scope
== RT_SCOPE_LINK
)
376 /* Force re-reading resolv file right now, for luck. */
377 daemon
->last_resolv
= 0;
379 if (daemon
->srv_save
)
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
;
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());
396 else if (h
->nlmsg_type
== RTM_NEWADDR
|| h
->nlmsg_type
== RTM_DELADDR
)
397 return 1; /* clever bind mode - rescan */