]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/netlink.c
1 /* dnsmasq is Copyright (c) 2000-2015 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 void 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;
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(retry_send(sendto(daemon
->netlinkfd
, (void *)&req
, sizeof(req
), 0,
173 (struct sockaddr
*)&addr
, sizeof(addr
))));
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 */
196 else if (h
->nlmsg_type
== NLMSG_DONE
)
198 else if (h
->nlmsg_type
== RTM_NEWADDR
&& family
!= AF_UNSPEC
&& family
!= AF_LOCAL
)
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
));
204 if (ifa
->ifa_family
== family
)
206 if (ifa
->ifa_family
== AF_INET
)
208 struct in_addr netmask
, addr
, broadcast
;
211 netmask
.s_addr
= htonl(~(in_addr_t
)0 << (32 - ifa
->ifa_prefixlen
));
214 broadcast
.s_addr
= 0;
216 while (RTA_OK(rta
, len1
))
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));
222 else if (rta
->rta_type
== IFA_LABEL
)
223 label
= RTA_DATA(rta
);
225 rta
= RTA_NEXT(rta
, len1
);
228 if (addr
.s_addr
&& callback_ok
)
229 if (!((*callback
)(addr
, ifa
->ifa_index
, label
, netmask
, broadcast
, parm
)))
233 else if (ifa
->ifa_family
== AF_INET6
)
235 struct in6_addr
*addrp
= NULL
;
236 u32 valid
= 0, preferred
= 0;
239 while (RTA_OK(rta
, len1
))
241 if (rta
->rta_type
== IFA_ADDRESS
)
242 addrp
= ((struct in6_addr
*)(rta
+1));
243 else if (rta
->rta_type
== IFA_CACHEINFO
)
245 struct ifa_cacheinfo
*ifc
= (struct ifa_cacheinfo
*)(rta
+1);
246 preferred
= ifc
->ifa_prefered
;
247 valid
= ifc
->ifa_valid
;
249 rta
= RTA_NEXT(rta
, len1
);
252 if (ifa
->ifa_flags
& IFA_F_TENTATIVE
)
253 flags
|= IFACE_TENTATIVE
;
255 if (ifa
->ifa_flags
& IFA_F_DEPRECATED
)
256 flags
|= IFACE_DEPRECATED
;
258 if (!(ifa
->ifa_flags
& IFA_F_TEMPORARY
))
259 flags
|= IFACE_PERMANENT
;
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
)))
270 else if (h
->nlmsg_type
== RTM_NEWNEIGH
&& family
== AF_UNSPEC
)
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
));
276 char *inaddr
= NULL
, *mac
= NULL
;
278 while (RTA_OK(rta
, len1
))
280 if (rta
->rta_type
== NDA_DST
)
281 inaddr
= (char *)(rta
+1);
282 else if (rta
->rta_type
== NDA_LLADDR
)
284 maclen
= rta
->rta_len
- sizeof(struct rtattr
);
285 mac
= (char *)(rta
+1);
288 rta
= RTA_NEXT(rta
, len1
);
291 if (inaddr
&& mac
&& callback_ok
)
292 if (!((*callback
)(neigh
->ndm_family
, inaddr
, mac
, maclen
, parm
)))
296 else if (h
->nlmsg_type
== RTM_NEWLINK
&& family
== AF_LOCAL
)
298 struct ifinfomsg
*link
= NLMSG_DATA(h
);
299 struct rtattr
*rta
= IFLA_RTA(link
);
300 unsigned int len1
= h
->nlmsg_len
- NLMSG_LENGTH(sizeof(*link
));
304 while (RTA_OK(rta
, len1
))
306 if (rta
->rta_type
== IFLA_ADDRESS
)
308 maclen
= rta
->rta_len
- sizeof(struct rtattr
);
309 mac
= (char *)(rta
+1);
312 rta
= RTA_NEXT(rta
, len1
);
315 if (mac
&& callback_ok
&& !((link
->ifi_flags
& (IFF_LOOPBACK
| IFF_POINTOPOINT
))) &&
316 !((*callback
)((int)link
->ifi_index
, (unsigned int)link
->ifi_type
, mac
, maclen
, parm
)))
323 void netlink_multicast(void)
329 /* don't risk blocking reading netlink messages here. */
330 if ((flags
= fcntl(daemon
->netlinkfd
, F_GETFL
)) == -1 ||
331 fcntl(daemon
->netlinkfd
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
334 if ((len
= netlink_recv()) != -1)
335 for (h
= (struct nlmsghdr
*)iov
.iov_base
; NLMSG_OK(h
, (size_t)len
); h
= NLMSG_NEXT(h
, len
))
338 /* restore non-blocking status */
339 fcntl(daemon
->netlinkfd
, F_SETFL
, flags
);
342 static void nl_async(struct nlmsghdr
*h
)
344 if (h
->nlmsg_type
== NLMSG_ERROR
)
346 struct nlmsgerr
*err
= NLMSG_DATA(h
);
348 my_syslog(LOG_ERR
, _("netlink returns error: %s"), strerror(-(err
->error
)));
350 else if (h
->nlmsg_pid
== 0 && h
->nlmsg_type
== RTM_NEWROUTE
)
352 /* We arrange to receive netlink multicast messages whenever the network route is added.
353 If this happens and we still have a DNS packet in the buffer, we re-send it.
354 This helps on DoD links, where frequently the packet which triggers dialling is
355 a DNS query, which then gets lost. By re-sending, we can avoid the lookup
357 struct rtmsg
*rtm
= NLMSG_DATA(h
);
359 if (rtm
->rtm_type
== RTN_UNICAST
&& rtm
->rtm_scope
== RT_SCOPE_LINK
)
360 queue_event(EVENT_NEWROUTE
);
362 else if (h
->nlmsg_type
== RTM_NEWADDR
|| h
->nlmsg_type
== RTM_DELADDR
)
363 queue_event(EVENT_NEWADDR
);