2 * interface monitor by Pontus Fuchs <pontus.fuchs@gmail.com>
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0+*/
14 #include <caputils/iface_monitor.h>
15 #include "ws_attributes.h"
17 #if defined(HAVE_LIBNL)
28 #include <netlink/msg.h>
30 #include <netlink/attr.h>
32 #include <netlink/route/link.h>
37 * Apparently, some versions of libnl drag in headers that define IFF_UP
38 * and others don't. Include <net/if.h> iff IFF_UP isn't already defined,
39 * so that if <linux/if.h> has been included by some or all of the
40 * netlink headers, we don't include <net/if.h> and get a bunch of
41 * complaints about various structures being redefined.
46 /* libnl 1.x compatibility code */
48 #define nl_sock nl_handle
49 #define nl_socket_disable_seq_check nl_disable_sequence_check
51 static inline struct nl_handle *nl_socket_alloc(void)
53 return nl_handle_alloc();
56 static inline void nl_socket_free(struct nl_sock *h)
60 #endif /* HAVE_LIBNL1 */
62 static struct nl_sock *iface_mon_sock;
65 iface_mon_handler2(struct nl_object *obj, void *arg)
67 struct rtnl_link *filter;
68 struct rtnl_link *link_obj;
71 iface_mon_cb cb = (iface_mon_cb)arg;
73 filter = rtnl_link_alloc();
75 fprintf(stderr, "error allocating filter\n");
79 if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
80 rtnl_link_put(filter);
84 link_obj = (struct rtnl_link *) obj;
85 flags = rtnl_link_get_flags (link_obj);
86 ifname = rtnl_link_get_name(link_obj);
89 * You can't bind a PF_PACKET socket to an interface that's not
90 * up, so an interface going down is an "interface should be
91 * removed" indication.
93 * XXX - what indication, if any, do we get if the interface
94 * *completely goes away*?
96 * XXX - can we get events if an interface's link-layer or
97 * network addresses change?
99 up = (flags & IFF_UP) ? 1 : 0;
103 rtnl_link_put(filter);
109 iface_mon_handler(struct nl_msg *msg, void *arg)
111 nl_msg_parse (msg, &iface_mon_handler2, arg);
116 iface_mon_event(void)
118 nl_recvmsgs_default(iface_mon_sock);
122 iface_mon_get_sock(void)
124 return nl_socket_get_fd(iface_mon_sock);
128 iface_mon_start(iface_mon_cb cb)
132 iface_mon_sock = nl_socket_alloc();
133 if (!iface_mon_sock) {
134 fprintf(stderr, "Failed to allocate netlink socket.\n");
138 nl_socket_disable_seq_check(iface_mon_sock);
140 nl_socket_modify_cb(iface_mon_sock, NL_CB_VALID, NL_CB_CUSTOM, iface_mon_handler, (void *)cb);
142 if (nl_connect(iface_mon_sock, NETLINK_ROUTE)) {
143 fprintf(stderr, "Failed to connect to generic netlink.\n");
145 goto out_handle_destroy;
148 nl_socket_add_membership(iface_mon_sock, RTNLGRP_LINK);
153 nl_socket_free(iface_mon_sock);
161 nl_socket_free(iface_mon_sock);
162 iface_mon_sock = NULL;
165 #elif defined(__APPLE__)
176 #include <sys/socket.h>
177 #include <sys/ioctl.h>
178 #include <sys/types.h>
180 #include <sys/kern_event.h>
185 static iface_mon_cb callback;
188 iface_mon_start(iface_mon_cb cb)
191 struct kev_request key;
193 /* Create a socket of type PF_SYSTEM to listen for events. */
194 s = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
199 * Ask for DLIL messages.
201 * XXX - also ask for KEV_INET_SUBCLASS and KEV_INET6_SUBCLASS,
202 * to detect new or changed network addresses, so those can be
203 * updated as well? Can we specify multiple filters on a socket,
204 * or must we specify KEV_ANY_SUBCLASS and filter the events after
207 key.vendor_code = KEV_VENDOR_APPLE;
208 key.kev_class = KEV_NETWORK_CLASS;
209 key.kev_subclass = KEV_DL_SUBCLASS;
210 if (ioctl(s, SIOCSKEVFILT, &key) == -1) {
227 iface_mon_get_sock(void)
233 * Size of buffer for kernel network event.
235 #define NET_EVENT_DATA_SIZE (KEV_MSG_HEADER_SIZE + sizeof (struct net_event_data))
238 iface_mon_event(void)
240 char msg[NET_EVENT_DATA_SIZE];
242 struct kern_event_msg *kem;
243 struct net_event_data *evd;
245 char ifr_name[IFNAMSIZ];
247 received = recv(s, msg, sizeof msg, 0);
249 /* Error - ignore. */
252 if ((size_t)received < sizeof msg) {
253 /* Short read - ignore. */
256 kem = (struct kern_event_msg *)msg;
257 evd_len = kem->total_size - KEV_MSG_HEADER_SIZE;
258 if (evd_len != sizeof (struct net_event_data)) {
259 /* Length of the message is bogus. */
262 evd = (struct net_event_data *)&kem->event_data[0];
263 g_snprintf(ifr_name, IFNAMSIZ, "%s%u", evd->if_name, evd->if_unit);
266 * Check type of event.
268 * Note: if we also ask for KEV_INET_SUBCLASS, we will get
272 * KEV_INET_CHANGED_ADDR
273 * KEV_INET_CHANGED_ADDR
274 * KEV_INET_SIFDSTADDR
275 * KEV_INET_SIFBRDADDR
276 * KEV_INET_SIFNETMASK
278 * reflecting network address changes, with the data being a
279 * struct kev_in_data rather than struct net_event_data, and
280 * if we also ask for KEV_INET6_SUBCLASS, we will get events
283 * KEV_INET6_NEW_LL_ADDR
284 * KEV_INET6_NEW_USER_ADDR
285 * KEV_INET6_NEW_RTADV_ADDR
286 * KEV_INET6_ADDR_DELETED
288 * with the data being a struct kev_in6_data.
290 switch (kem->event_code) {
292 case KEV_DL_IF_ATTACHED:
294 * A new interface has arrived.
296 * XXX - what we really want is "a new BPFable interface
297 * has arrived", but that's not available. While we're
298 * asking for additional help from BPF, it'd also be
299 * nice if we could ask it for a list of all interfaces
300 * that have had bpfattach()/bpf_attach() done on them,
301 * so we don't have to try to open the device in order
302 * to see whether we should show it as something on
303 * which we can capture.
305 callback(ifr_name, 1);
308 case KEV_DL_IF_DETACHED:
310 * An existing interface has been removed.
312 * XXX - use KEV_DL_IF_DETACHING instead, as that's
313 * called shortly after bpfdetach() is called, and
314 * bpfdetach() makes an interface no longer BPFable,
315 * and that's what we *really* care about.
317 callback(ifr_name, 0);
322 * Is there any reason to care about:
327 * KEV_DL_LINK_ADDRESS_CHANGED
328 * KEV_DL_IFCAP_CHANGED
330 * or any of the other events? On Snow Leopard and, I think,
331 * earlier releases, you can't attach a BPF device to an
332 * interface that's not up, so KEV_DL_SIFFLAGS might be
333 * worth listening to so that we only say "here's a new
334 * interface" when it goes up; on Lion (and possibly Mountain
335 * Lion), an interface doesn't have to be up in order to
336 * have a BPF device attached to it.
342 #else /* don't have something we support */
345 iface_mon_start(iface_mon_cb cb _U_)
356 iface_mon_get_sock(void)
362 iface_mon_event(void)
366 #endif /* HAVE_LIBNL */
368 #endif /* HAVE_LIBPCAP */
371 * Editor modelines - http://www.wireshark.org/tools/modelines.html
376 * indent-tabs-mode: nil
379 * vi: set shiftwidth=4 tabstop=8 expandtab:
380 * :indentSize=4:tabSize=8:noTabs=true: