xref: /freebsd/contrib/libpcap/pcap-haiku.c (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
1 /*
2  * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		James Woodcock
8  */
9 
10 
11 #include <config.h>
12 #include "pcap-int.h"
13 
14 #include <OS.h>
15 
16 #include <sys/socket.h>
17 #include <sys/sockio.h>
18 #include <sys/utsname.h>
19 
20 #include <net/if.h>
21 #include <net/if_dl.h>
22 #include <net/if_types.h>
23 #include <net/if_media.h>
24 
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdint.h>
31 
32 
33 // IFT_TUN was renamed to IFT_TUNNEL in the master branch after R1/beta4 (the
34 // integer value didn't change).  Even though IFT_TUN is a no-op in versions
35 // that define it, for the time being it is desirable to support compiling
36 // libpcap on versions with the old macro and using it on later versions that
37 // support tunnel interfaces.
38 #ifndef IFT_TUNNEL
39 #define IFT_TUNNEL IFT_TUN
40 #endif
41 
42 /*
43  * Private data for capturing on Haiku sockets.
44  */
45 struct pcap_haiku {
46 	struct pcap_stat	stat;
47 	int aux_socket;
48 	struct ifreq ifreq;
49 	// The original state of the promiscuous mode at the activation time,
50 	// if the capture should be run in promiscuous mode.
51 	int orig_promisc;
52 };
53 
54 
55 static int
56 pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback,
57 	u_char* userdata)
58 {
59 	// Receive a single packet
60 
61 	u_char* buffer = (u_char*)handle->buffer;
62 	ssize_t bytesReceived;
63 	do {
64 		if (handle->break_loop) {
65 			handle->break_loop = 0;
66 			return PCAP_ERROR_BREAK;
67 		}
68 		bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC,
69 		                         NULL, NULL);
70 	} while (bytesReceived < 0 && errno == B_INTERRUPTED);
71 
72 	// The kernel does not implement timestamping of network packets, so
73 	// doing it ASAP in userland is the best that can be done.
74 	bigtime_t ts = real_time_clock_usecs();
75 
76 	if (bytesReceived < 0) {
77 		if (errno == B_WOULD_BLOCK) {
78 			// there is no packet for us
79 			return 0;
80 		}
81 
82 		pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
83 		    errno, "recvfrom");
84 		return PCAP_ERROR;
85 	}
86 
87 	struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
88 	// BPF is 32-bit, which is more than sufficient for any realistic
89 	// packet size.
90 	if (bytesReceived > UINT32_MAX)
91 		goto drop;
92 	// At this point, if the recvfrom() call populated its struct sockaddr
93 	// and socklen_t arguments, it would be the right time to drop packets
94 	// that have .sa_family not valid for the current DLT.  But in the
95 	// current master branch (hrev57588) this would erroneously drop some
96 	// valid packets: recvfrom(), at least for tap mode tunnels, sets the
97 	// address length to 0 for all incoming packets and sets .sa_len and
98 	// .sa_family to 0 for packets that are broadcast or multicast.  So it
99 	// cannot be done yet, if there is a good reason to do it in the first
100 	// place.
101 	handlep->stat.ps_recv++;
102 
103 	bpf_u_int32 wireLength = (bpf_u_int32)bytesReceived;
104 	// As long as the buffer is large enough, the captured length is equal
105 	// to the wire length, but let's get the lengths right anyway in case
106 	// packets grow bigger or the buffer grows smaller in future and the
107 	// MSG_TRUNC effect kicks in.
108 	bpf_u_int32 captureLength =
109 		wireLength <= handle->bufsize ? wireLength : handle->bufsize;
110 
111 	// run the packet filter
112 	if (handle->fcode.bf_insns) {
113 		// NB: pcapint_filter() takes the wire length and the captured
114 		// length, not the snapshot length of the pcap_t handle.
115 		if (pcapint_filter(handle->fcode.bf_insns, buffer, wireLength,
116 		                   captureLength) == 0)
117 			goto drop;
118 	}
119 
120 	// fill in pcap_header
121 	struct pcap_pkthdr header;
122 	header.caplen = captureLength <= (bpf_u_int32)handle->snapshot ?
123 	                captureLength :
124 	                (bpf_u_int32)handle->snapshot;
125 	header.len = wireLength;
126 	header.ts.tv_usec = ts % 1000000;
127 	header.ts.tv_sec = ts / 1000000;
128 
129 	/* Call the user supplied callback function */
130 	callback(userdata, &header, buffer);
131 	return 1;
132 drop:
133 	handlep->stat.ps_drop++;
134 	return 0;
135 }
136 
137 
138 static int
139 dgram_socket(const int af, char *errbuf)
140 {
141 	int ret = socket(af, SOCK_DGRAM, 0);
142 	if (ret < 0) {
143 		pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
144 		    "socket");
145 		return PCAP_ERROR;
146 	}
147 	return ret;
148 }
149 
150 
151 static int
152 ioctl_ifreq(const int fd, const unsigned long op, const char *name,
153              struct ifreq *ifreq, char *errbuf)
154 {
155 	if (ioctl(fd, op, ifreq, sizeof(struct ifreq)) < 0) {
156 		pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
157 		    "%s", name);
158 		return PCAP_ERROR;
159 	}
160 	return 0;
161 }
162 
163 
164 static int
165 get_promisc(pcap_t *handle)
166 {
167 	struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv;
168 	// SIOCGIFFLAGS would work fine for AF_LINK too.
169 	if (ioctl_ifreq(handlep->aux_socket, SIOCGIFFLAGS, "SIOCGIFFLAGS",
170 	                &handlep->ifreq, handle->errbuf) < 0)
171 		return PCAP_ERROR;
172 	return (handlep->ifreq.ifr_flags & IFF_PROMISC) != 0;
173 }
174 
175 
176 static int
177 set_promisc(pcap_t *handle, const int enable)
178 {
179 	struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv;
180 	if (enable)
181 		handlep->ifreq.ifr_flags |= IFF_PROMISC;
182 	else
183 		handlep->ifreq.ifr_flags &= ~IFF_PROMISC;
184 	// SIOCSIFFLAGS works for AF_INET, but not for AF_LINK.
185 	return ioctl_ifreq(handlep->aux_socket, SIOCSIFFLAGS, "SIOCSIFFLAGS",
186 	                   &handlep->ifreq, handle->errbuf);
187 }
188 
189 
190 static void
191 pcap_cleanup_haiku(pcap_t *handle)
192 {
193 	struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv;
194 	if (handlep->aux_socket >= 0) {
195 		// Closing the sockets has no effect on IFF_PROMISC, hence the
196 		// need to restore the original state on one hand and the
197 		// possibility of clash with other processes managing the same
198 		// interface flag.  Unset promiscuous mode iff the activation
199 		// function had set it and it is still set now.
200 		if (handle->opt.promisc && ! handlep->orig_promisc &&
201 		    get_promisc(handle))
202 			(void)set_promisc(handle, 0);
203 		close(handlep->aux_socket);
204 		handlep->aux_socket = -1;
205 	}
206 	pcapint_cleanup_live_common(handle);
207 }
208 
209 
210 static int
211 pcap_inject_haiku(pcap_t *handle, const void *buffer _U_, int size _U_)
212 {
213 	// Haiku currently (hrev57588) does not support sending raw packets.
214 	// https://dev.haiku-os.org/ticket/18810
215 	strlcpy(handle->errbuf, "Sending packets isn't supported yet",
216 		PCAP_ERRBUF_SIZE);
217 	return PCAP_ERROR;
218 }
219 
220 
221 static int
222 pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
223 {
224 	struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
225 	*stats = handlep->stat;
226 	// Now ps_recv and ps_drop are accurate, but ps_ifdrop still equals to
227 	// the snapshot value from the activation time.
228 	if (ioctl_ifreq(handlep->aux_socket, SIOCGIFSTATS, "SIOCGIFSTATS",
229 	                &handlep->ifreq, handle->errbuf) < 0)
230 		return PCAP_ERROR;
231 	// The result is subject to wrapping around the 32-bit integer space,
232 	// but that cannot be significantly improved as long as it has to fit
233 	// into a 32-bit member of pcap_stats.
234 	stats->ps_ifdrop = handlep->ifreq.ifr_stats.receive.dropped - stats->ps_ifdrop;
235 	return 0;
236 }
237 
238 
239 static int
240 pcap_activate_haiku(pcap_t *handle)
241 {
242 	struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv;
243 	int ret = PCAP_ERROR;
244 
245 	// we need a socket to talk to the networking stack
246 	if ((handlep->aux_socket = dgram_socket(AF_INET, handle->errbuf)) < 0)
247 		goto error;
248 
249 	// pcap_stats_haiku() will need a baseline for ps_ifdrop.
250 	// At the time of this writing SIOCGIFSTATS returns EINVAL for AF_LINK
251 	// sockets.
252 	if (ioctl_ifreq(handlep->aux_socket, SIOCGIFSTATS, "SIOCGIFSTATS",
253 	                &handlep->ifreq, handle->errbuf) < 0) {
254 		// Detect a non-existent network interface at least at the
255 		// first ioctl() use.
256 		if (errno == EINVAL)
257 			ret = PCAP_ERROR_NO_SUCH_DEVICE;
258 		goto error;
259 	}
260 	handlep->stat.ps_ifdrop = handlep->ifreq.ifr_stats.receive.dropped;
261 
262 	// get link level interface for this interface
263 	if ((handle->fd = dgram_socket(AF_LINK, handle->errbuf)) < 0)
264 		goto error;
265 
266 	// Derive a DLT from the interface type.
267 	// At the time of this writing SIOCGIFTYPE cannot be used for this
268 	// purpose: it returns EINVAL for AF_LINK sockets and sets ifr_type to
269 	// 0 for AF_INET sockets.  Use the same method as Haiku ifconfig does
270 	// (SIOCGIFADDR and AF_LINK).
271 	if (ioctl_ifreq(handle->fd, SIOCGIFADDR, "SIOCGIFADDR",
272 	                &handlep->ifreq, handle->errbuf) < 0)
273 		goto error;
274 	struct sockaddr_dl *sdl = (struct sockaddr_dl *)&handlep->ifreq.ifr_addr;
275 	if (sdl->sdl_family != AF_LINK) {
276 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
277 		         "Got AF %d instead of AF_LINK for interface \"%s\".",
278 		         sdl->sdl_family, handle->opt.device);
279 		goto error;
280 	}
281 	switch (sdl->sdl_type) {
282 	case IFT_ETHER:
283 		// Ethernet on all versions, also tap (L2) mode tunnels on
284 		// versions after R1/beta4.
285 		handle->linktype = DLT_EN10MB;
286 		break;
287 	case IFT_TUNNEL:
288 		// Unused on R1/beta4 and earlier versions, tun (L3) mode
289 		// tunnels on later versions.
290 	case IFT_LOOP:
291 		// The loopback interface on all versions.
292 		// Both IFT_TUNNEL and IFT_LOOP prepended a dummy Ethernet
293 		// header until hrev57585: https://dev.haiku-os.org/ticket/18801
294 		handle->linktype = DLT_RAW;
295 		break;
296 	default:
297 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
298 		         "Unknown interface type 0x%0x for interface \"%s\".",
299 		         sdl->sdl_type, handle->opt.device);
300 		goto error;
301 	}
302 
303 	// start monitoring
304 	if (ioctl_ifreq(handle->fd, SIOCSPACKETCAP, "SIOCSPACKETCAP",
305 	                &handlep->ifreq, handle->errbuf) < 0)
306 		goto error;
307 
308 	handle->selectable_fd = handle->fd;
309 	handle->read_op = pcap_read_haiku;
310 	handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */
311 	handle->inject_op = pcap_inject_haiku;
312 	handle->stats_op = pcap_stats_haiku;
313 	handle->cleanup_op = pcap_cleanup_haiku;
314 
315 	// use default hooks where possible
316 	handle->getnonblock_op = pcapint_getnonblock_fd;
317 	handle->setnonblock_op = pcapint_setnonblock_fd;
318 
319 	/*
320 	 * Turn a negative snapshot value (invalid), a snapshot value of
321 	 * 0 (unspecified), or a value bigger than the normal maximum
322 	 * value, into the maximum allowed value.
323 	 *
324 	 * If some application really *needs* a bigger snapshot
325 	 * length, we should just increase MAXIMUM_SNAPLEN.
326 	 */
327 	if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
328 		handle->snapshot = MAXIMUM_SNAPLEN;
329 
330 	// Although it would be trivial to size the buffer at the kernel end of
331 	// the capture socket using setsockopt() and SO_RCVBUF, there seems to
332 	// be no point in doing so: setting the size low silently drops some
333 	// packets in the kernel, setting it high does not result in a visible
334 	// improvement.  Let's leave this buffer as it is until it is clear why
335 	// it would need resizing.  Meanwhile pcap_set_buffer_size() will have
336 	// no effect on Haiku.
337 
338 	// It would be wrong to size the buffer at the libpcap end of the
339 	// capture socket to the interface MTU, which limits only outgoing
340 	// packets and only at layer 3.  For example, an Ethernet interface
341 	// with ifconfig/ioctl() MTU set to 1500 ordinarily sends layer 2
342 	// packets as large as 1514 bytes and receives layer 2 packets as large
343 	// as the NIC and the driver happen to accept (e.g. 9018 bytes for
344 	// ipro1000).  This way, valid packets larger than the MTU can occur in
345 	// a capture and will arrive truncated to pcap_read_haiku() if the
346 	// buffer is not large enough.  So let's keep it large enough for most
347 	// if not all practical use cases, then pcap_read_haiku() can handle
348 	// the unlikely truncation as and if necessary.
349 	handle->bufsize = 65536;
350 
351 	// allocate buffer for monitoring the device
352 	handle->buffer = (u_char*)malloc(handle->bufsize);
353 	if (handle->buffer == NULL) {
354 		pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
355 			errno, "buffer malloc");
356 		goto error;
357 	}
358 
359 	if (handle->opt.promisc) {
360 		// Set promiscuous mode iff required, in any case remember the
361 		// original state.
362 		if ((handlep->orig_promisc = get_promisc(handle)) < 0)
363 			goto error;
364 		if (! handlep->orig_promisc && set_promisc(handle, 1) < 0)
365 			return PCAP_WARNING_PROMISC_NOTSUP;
366 	}
367 	return 0;
368 error:
369 	pcap_cleanup_haiku(handle);
370 	return ret;
371 }
372 
373 
374 static int
375 validate_ifname(const char *device, char *errbuf)
376 {
377 	if (strlen(device) >= IF_NAMESIZE) {
378 		snprintf(errbuf, PCAP_ERRBUF_SIZE,
379 		         "Interface name \"%s\" is too long.", device);
380 		return PCAP_ERROR;
381 	}
382 	return 0;
383 }
384 
385 
386 //	#pragma mark - pcap API
387 
388 
389 static int
390 can_be_bound(const char *name)
391 {
392 	if (strcmp(name, "loop") != 0)
393 		return 1;
394 
395 	// In Haiku versions before hrev57010 the loopback interface allows to
396 	// start a capture, but the capture never receives any packets.
397 	//
398 	// Since compiling libpcap on one Haiku version and using the binary on
399 	// another seems to be commonplace, comparing B_HAIKU_VERSION at the
400 	// compile time would not always work as intended.  Let's at least
401 	// remove unsuitable well-known 64-bit versions (with or without
402 	// updates) from the problem space at run time.
403 	const char *badversions[] = {
404 		"hrev56578", // R1/beta4
405 		"hrev55182", // R1/beta3
406 		"hrev54154", // R1/beta2
407 		"hrev52295", // R1/beta1
408 		"hrev44702", // R1/alpha4
409 		NULL
410 	};
411 	struct utsname uts;
412 	(void)uname(&uts);
413 	for (const char **s = badversions; *s; s++)
414 		if (! strncmp(uts.version, *s, strlen(*s)))
415 			return 0;
416 	return 1;
417 }
418 
419 
420 pcap_t *
421 pcapint_create_interface(const char *device, char *errorBuffer)
422 {
423 	if (validate_ifname(device, errorBuffer) < 0)
424 		return NULL;
425 	if (! can_be_bound(device)) {
426 		snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
427 		         "Interface \"%s\" does not support capturing traffic.", device);
428 		return NULL;
429 	}
430 
431 	pcap_t* handle = PCAP_CREATE_COMMON(errorBuffer, struct pcap_haiku);
432 	if (handle == NULL)
433 		return NULL;
434 	handle->activate_op = pcap_activate_haiku;
435 
436 	struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv;
437 	handlep->aux_socket = -1;
438 	strcpy(handlep->ifreq.ifr_name, device);
439 
440 	return handle;
441 }
442 
443 
444 static int
445 get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
446 {
447 	if (validate_ifname(name, errbuf) < 0)
448 		return PCAP_ERROR;
449 
450 	if (*flags & PCAP_IF_LOOPBACK ||
451 	    ! strncmp(name, "tun", strlen("tun")) ||
452 	    ! strncmp(name, "tap", strlen("tap"))) {
453 		/*
454 		 * Loopback devices aren't wireless, and "connected"/
455 		 * "disconnected" doesn't apply to them.
456 		 *
457 		 * Neither does it to tunnel interfaces.  A tun mode tunnel
458 		 * can be identified by the IFT_TUNNEL value, but tap mode
459 		 * tunnels and Ethernet interfaces both use IFT_ETHER, so let's
460 		 * use the interface name prefix until there is a better
461 		 * solution.
462 		 */
463 		*flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
464 		return (0);
465 	}
466 
467 	int fd = dgram_socket(AF_LINK, errbuf);
468 	if (fd < 0)
469 		return PCAP_ERROR;
470 	struct ifreq ifreq;
471 	strcpy(ifreq.ifr_name, name);
472 	if (ioctl_ifreq(fd, SIOCGIFFLAGS, "SIOCGIFFLAGS", &ifreq, errbuf) < 0) {
473 		close(fd);
474 		return PCAP_ERROR;
475 	}
476 	*flags |= (ifreq.ifr_flags & IFF_LINK) ?
477 	          PCAP_IF_CONNECTION_STATUS_CONNECTED :
478 	          PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
479 	if (ioctl_ifreq(fd, SIOCGIFMEDIA, "SIOCGIFMEDIA", &ifreq, errbuf) < 0) {
480 		close(fd);
481 		return PCAP_ERROR;
482 	}
483 	if (IFM_TYPE(ifreq.ifr_media) == IFM_IEEE80211)
484 		*flags |= PCAP_IF_WIRELESS;
485 	close(fd);
486 
487 	return (0);
488 }
489 
490 int
491 pcapint_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
492 {
493 	return pcapint_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
494 		get_if_flags);
495 }
496 
497 /*
498  * Libpcap version string.
499  */
500 const char *
501 pcap_lib_version(void)
502 {
503 	return (PCAP_VERSION_STRING);
504 }
505