2 * interface monitor by Pontus Fuchs <pontus.fuchs@gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "iface_monitor.h"
30 #if defined(HAVE_LIBNL)
40 #if defined(HAVE_LIBNL1) || defined(HAVE_LIBNL2)
44 #include <netlink/msg.h>
45 #include <netlink/attr.h>
46 #include <netlink/route/link.h>
48 /* libnl 1.x compatibility code */
50 #define nl_sock nl_handle
51 #define nl_socket_disable_seq_check nl_disable_sequence_check
53 static inline struct nl_handle *nl_socket_alloc(void)
55 return nl_handle_alloc();
58 static inline void nl_socket_free(struct nl_sock *h)
62 #endif /* HAVE_LIBNL1 */
64 static struct nl_sock *iface_mon_sock;
67 iface_mon_handler2(struct nl_object *obj, void *arg)
69 struct rtnl_link *filter;
70 struct rtnl_link *link_obj;
73 iface_mon_cb cb = arg;
75 filter = rtnl_link_alloc();
77 fprintf(stderr, "error allocating filter\n");
81 if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
82 rtnl_link_put(filter);
86 link_obj = (struct rtnl_link *) obj;
87 flags = rtnl_link_get_flags (link_obj);
88 ifname = rtnl_link_get_name(link_obj);
91 * You can't bind a PF_PACKET socket to an interface that's not
92 * up, so an interface going down is an "interface should be
93 * removed" indication.
95 * XXX - what indication, if any, do we get if the interface
96 * *completely goes away*?
98 * XXX - can we get events if an interface's link-layer or
99 * network addresses change?
101 up = (flags & IFF_UP) ? 1 : 0;
105 rtnl_link_put(filter);
111 iface_mon_handler(struct nl_msg *msg, void *arg)
113 nl_msg_parse (msg, &iface_mon_handler2, arg);
118 iface_mon_event(void)
120 nl_recvmsgs_default(iface_mon_sock);
124 iface_mon_get_sock(void)
126 return nl_socket_get_fd(iface_mon_sock);
130 iface_mon_start(iface_mon_cb cb)
134 iface_mon_sock = nl_socket_alloc();
135 if (!iface_mon_sock) {
136 fprintf(stderr, "Failed to allocate netlink socket.\n");
140 nl_socket_disable_seq_check(iface_mon_sock);
142 nl_socket_modify_cb(iface_mon_sock, NL_CB_VALID, NL_CB_CUSTOM, iface_mon_handler, cb);
144 if (nl_connect(iface_mon_sock, NETLINK_ROUTE)) {
145 fprintf(stderr, "Failed to connect to generic netlink.\n");
147 goto out_handle_destroy;
150 nl_socket_add_membership(iface_mon_sock, RTNLGRP_LINK);
155 nl_socket_free(iface_mon_sock);
163 nl_socket_free(iface_mon_sock);
164 iface_mon_sock = NULL;
167 #elif defined(__APPLE__)
178 #include <sys/socket.h>
179 #include <sys/ioctl.h>
180 #include <sys/types.h>
182 #include <sys/kern_event.h>
187 static iface_mon_cb callback;
190 iface_mon_start(iface_mon_cb cb)
193 struct kev_request key;
195 /* Create a socket of type PF_SYSTEM to listen for events. */
196 s = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
201 * Ask for DLIL messages.
203 * XXX - also ask for KEV_INET_SUBCLASS and KEV_INET6_SUBCLASS,
204 * to detect new or changed network addresses, so those can be
205 * updated as well? Can we specify multiple filters on a socket,
206 * or must we specify KEV_ANY_SUBCLASS and filter the events after
209 key.vendor_code = KEV_VENDOR_APPLE;
210 key.kev_class = KEV_NETWORK_CLASS;
211 key.kev_subclass = KEV_DL_SUBCLASS;
212 if (ioctl(s, SIOCSKEVFILT, &key) == -1) {
229 iface_mon_get_sock(void)
235 * Size of buffer for kernel network event.
237 #define NET_EVENT_DATA_SIZE (KEV_MSG_HEADER_SIZE + sizeof (struct net_event_data))
240 iface_mon_event(void)
242 char msg[NET_EVENT_DATA_SIZE];
244 struct kern_event_msg *kem;
245 struct net_event_data *evd;
247 char ifr_name[IFNAMSIZ];
249 received = recv(s, msg, sizeof msg, 0);
251 /* Error - ignore. */
254 if ((size_t)received < sizeof msg) {
255 /* Short read - ignore. */
258 kem = (struct kern_event_msg *)msg;
259 evd_len = kem->total_size - KEV_MSG_HEADER_SIZE;
260 if (evd_len != sizeof (struct net_event_data)) {
261 /* Length of the message is bogus. */
264 evd = (struct net_event_data *)&kem->event_data[0];
265 g_snprintf(ifr_name, IFNAMSIZ, "%s%u", evd->if_name, evd->if_unit);
268 * Check type of event.
270 * Note: if we also ask for KEV_INET_SUBCLASS, we will get
274 * KEV_INET_CHANGED_ADDR
275 * KEV_INET_CHANGED_ADDR
276 * KEV_INET_SIFDSTADDR
277 * KEV_INET_SIFBRDADDR
278 * KEV_INET_SIFNETMASK
280 * reflecting network address changes, with the data being a
281 * struct kev_in_data rather than struct net_event_data, and
282 * if we also ask for KEV_INET6_SUBCLASS, we will get events
285 * KEV_INET6_NEW_LL_ADDR
286 * KEV_INET6_NEW_USER_ADDR
287 * KEV_INET6_NEW_RTADV_ADDR
288 * KEV_INET6_ADDR_DELETED
290 * with the data being a struct kev_in6_data.
292 switch (kem->event_code) {
294 case KEV_DL_IF_ATTACHED:
296 * A new interface has arrived.
298 * XXX - what we really want is "a new BPFable interface
299 * has arrived", but that's not available. While we're
300 * asking for additional help from BPF, it'd also be
301 * nice if we could ask it for a list of all interfaces
302 * that have had bpfattach()/bpf_attach() done on them,
303 * so we don't have to try to open the device in order
304 * to see whether we should show it as something on
305 * which we can capture.
307 callback(ifr_name, 1);
310 case KEV_DL_IF_DETACHED:
312 * An existing interface has been removed.
314 * XXX - use KEV_DL_IF_DETACHING instead, as that's
315 * called shortly after bpfdetach() is called, and
316 * bpfdetach() makes an interface no longer BPFable,
317 * and that's what we *really* care about.
319 callback(ifr_name, 0);
324 * Is there any reason to care about:
329 * KEV_DL_LINK_ADDRESS_CHANGED
330 * KEV_DL_IFCAP_CHANGED
332 * or any of the other events? On Snow Leopard and, I think,
333 * earlier releases, you can't attach a BPF device to an
334 * interface that's not up, so KEV_DL_SIFFLAGS might be
335 * worth listening to so that we only say "here's a new
336 * interface" when it goes up; on Lion (and possibly Mountain
337 * Lion), an interface doesn't have to be up in order to
338 * have a BPF device attached to it.
344 #else /* don't have something we support */
347 iface_mon_start(iface_mon_cb cb _U_)
358 iface_mon_get_sock(void)
364 iface_mon_event(void)
368 #endif /* HAVE_LIBNL */
370 #endif /* HAVE_LIBPCAP */