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 #include <netlink/msg.h>
41 #include <netlink/attr.h>
42 #include <netlink/route/link.h>
46 * Apparently, some versions of libnl drag in headers that define IFF_UP
47 * and others don't. Include <net/if.h> iff IFF_UP isn't already defined,
48 * so that if <linux/if.h> has been included by some or all of the
49 * netlink headers, we don't include <net/if.h> and get a bunch of
50 * complaints about various structures being redefined.
55 /* libnl 1.x compatibility code */
57 #define nl_sock nl_handle
58 #define nl_socket_disable_seq_check nl_disable_sequence_check
60 static inline struct nl_handle
*nl_socket_alloc(void)
62 return nl_handle_alloc();
65 static inline void nl_socket_free(struct nl_sock
*h
)
69 #endif /* HAVE_LIBNL1 */
71 static struct nl_sock
*iface_mon_sock
;
74 iface_mon_handler2(struct nl_object
*obj
, void *arg
)
76 struct rtnl_link
*filter
;
77 struct rtnl_link
*link_obj
;
80 iface_mon_cb cb
= (iface_mon_cb
)arg
;
82 filter
= rtnl_link_alloc();
84 fprintf(stderr
, "error allocating filter\n");
88 if (nl_object_match_filter (obj
, OBJ_CAST (filter
)) == 0) {
89 rtnl_link_put(filter
);
93 link_obj
= (struct rtnl_link
*) obj
;
94 flags
= rtnl_link_get_flags (link_obj
);
95 ifname
= rtnl_link_get_name(link_obj
);
98 * You can't bind a PF_PACKET socket to an interface that's not
99 * up, so an interface going down is an "interface should be
100 * removed" indication.
102 * XXX - what indication, if any, do we get if the interface
103 * *completely goes away*?
105 * XXX - can we get events if an interface's link-layer or
106 * network addresses change?
108 up
= (flags
& IFF_UP
) ? 1 : 0;
112 rtnl_link_put(filter
);
118 iface_mon_handler(struct nl_msg
*msg
, void *arg
)
120 nl_msg_parse (msg
, &iface_mon_handler2
, arg
);
125 iface_mon_event(void)
127 nl_recvmsgs_default(iface_mon_sock
);
131 iface_mon_get_sock(void)
133 return nl_socket_get_fd(iface_mon_sock
);
137 iface_mon_start(iface_mon_cb cb
)
141 iface_mon_sock
= nl_socket_alloc();
142 if (!iface_mon_sock
) {
143 fprintf(stderr
, "Failed to allocate netlink socket.\n");
147 nl_socket_disable_seq_check(iface_mon_sock
);
149 nl_socket_modify_cb(iface_mon_sock
, NL_CB_VALID
, NL_CB_CUSTOM
, iface_mon_handler
, cb
);
151 if (nl_connect(iface_mon_sock
, NETLINK_ROUTE
)) {
152 fprintf(stderr
, "Failed to connect to generic netlink.\n");
154 goto out_handle_destroy
;
157 nl_socket_add_membership(iface_mon_sock
, RTNLGRP_LINK
);
162 nl_socket_free(iface_mon_sock
);
170 nl_socket_free(iface_mon_sock
);
171 iface_mon_sock
= NULL
;
174 #elif defined(__APPLE__)
185 #include <sys/socket.h>
186 #include <sys/ioctl.h>
187 #include <sys/types.h>
189 #include <sys/kern_event.h>
194 static iface_mon_cb callback
;
197 iface_mon_start(iface_mon_cb cb
)
200 struct kev_request key
;
202 /* Create a socket of type PF_SYSTEM to listen for events. */
203 s
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
208 * Ask for DLIL messages.
210 * XXX - also ask for KEV_INET_SUBCLASS and KEV_INET6_SUBCLASS,
211 * to detect new or changed network addresses, so those can be
212 * updated as well? Can we specify multiple filters on a socket,
213 * or must we specify KEV_ANY_SUBCLASS and filter the events after
216 key
.vendor_code
= KEV_VENDOR_APPLE
;
217 key
.kev_class
= KEV_NETWORK_CLASS
;
218 key
.kev_subclass
= KEV_DL_SUBCLASS
;
219 if (ioctl(s
, SIOCSKEVFILT
, &key
) == -1) {
236 iface_mon_get_sock(void)
242 * Size of buffer for kernel network event.
244 #define NET_EVENT_DATA_SIZE (KEV_MSG_HEADER_SIZE + sizeof (struct net_event_data))
247 iface_mon_event(void)
249 char msg
[NET_EVENT_DATA_SIZE
];
251 struct kern_event_msg
*kem
;
252 struct net_event_data
*evd
;
254 char ifr_name
[IFNAMSIZ
];
256 received
= recv(s
, msg
, sizeof msg
, 0);
258 /* Error - ignore. */
261 if ((size_t)received
< sizeof msg
) {
262 /* Short read - ignore. */
265 kem
= (struct kern_event_msg
*)msg
;
266 evd_len
= kem
->total_size
- KEV_MSG_HEADER_SIZE
;
267 if (evd_len
!= sizeof (struct net_event_data
)) {
268 /* Length of the message is bogus. */
271 evd
= (struct net_event_data
*)&kem
->event_data
[0];
272 g_snprintf(ifr_name
, IFNAMSIZ
, "%s%u", evd
->if_name
, evd
->if_unit
);
275 * Check type of event.
277 * Note: if we also ask for KEV_INET_SUBCLASS, we will get
281 * KEV_INET_CHANGED_ADDR
282 * KEV_INET_CHANGED_ADDR
283 * KEV_INET_SIFDSTADDR
284 * KEV_INET_SIFBRDADDR
285 * KEV_INET_SIFNETMASK
287 * reflecting network address changes, with the data being a
288 * struct kev_in_data rather than struct net_event_data, and
289 * if we also ask for KEV_INET6_SUBCLASS, we will get events
292 * KEV_INET6_NEW_LL_ADDR
293 * KEV_INET6_NEW_USER_ADDR
294 * KEV_INET6_NEW_RTADV_ADDR
295 * KEV_INET6_ADDR_DELETED
297 * with the data being a struct kev_in6_data.
299 switch (kem
->event_code
) {
301 case KEV_DL_IF_ATTACHED
:
303 * A new interface has arrived.
305 * XXX - what we really want is "a new BPFable interface
306 * has arrived", but that's not available. While we're
307 * asking for additional help from BPF, it'd also be
308 * nice if we could ask it for a list of all interfaces
309 * that have had bpfattach()/bpf_attach() done on them,
310 * so we don't have to try to open the device in order
311 * to see whether we should show it as something on
312 * which we can capture.
314 callback(ifr_name
, 1);
317 case KEV_DL_IF_DETACHED
:
319 * An existing interface has been removed.
321 * XXX - use KEV_DL_IF_DETACHING instead, as that's
322 * called shortly after bpfdetach() is called, and
323 * bpfdetach() makes an interface no longer BPFable,
324 * and that's what we *really* care about.
326 callback(ifr_name
, 0);
331 * Is there any reason to care about:
336 * KEV_DL_LINK_ADDRESS_CHANGED
337 * KEV_DL_IFCAP_CHANGED
339 * or any of the other events? On Snow Leopard and, I think,
340 * earlier releases, you can't attach a BPF device to an
341 * interface that's not up, so KEV_DL_SIFFLAGS might be
342 * worth listening to so that we only say "here's a new
343 * interface" when it goes up; on Lion (and possibly Mountain
344 * Lion), an interface doesn't have to be up in order to
345 * have a BPF device attached to it.
351 #else /* don't have something we support */
354 iface_mon_start(iface_mon_cb cb _U_
)
365 iface_mon_get_sock(void)
371 iface_mon_event(void)
375 #endif /* HAVE_LIBNL */
377 #endif /* HAVE_LIBPCAP */