]> The Tcpdump Group git mirrors - libpcap/blob - pcap-linux.c
fa83dae01e68c2ee8cc0a0644220dc6eef25dcd9
[libpcap] / pcap-linux.c
1 /*
2 pcap-linux.c: Packet capture interface to the Linux kernel
3 Copyright (c) 2000 Torsten Landschoff <torsten@debian.org>
4 Sebastian Krahmer <krahmer@cs.uni-potsdam.de>
5
6 License: BSD
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in
16 the documentation and/or other materials provided with the
17 distribution.
18 3. The names of the authors may not be used to endorse or promote
19 products derived from this software without specific prior
20 written permission.
21
22 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 */
26
27 /*
28 TODO:
29
30 - Make it compatible with older Linux installations (at compilation time)
31
32 BUGS:
33
34 - setting promiscuous on loopback for example gives every packet
35 twice
36 */
37
38
39 /*
40 FYI:
41
42 pcap_read currently reads not only a packet from the kernel but also
43 the sockaddr_ll returned as source of the packet. This way we can at
44 some time extend tcpdump and libpcap to sniff on all devices at a time
45 and find the right printing routine by using the information in the
46 sockaddr_ll structure.
47 */
48
49
50 #ifdef HAVE_CONFIG_H
51 #include "config.h"
52 #endif
53
54 #include "pcap-int.h"
55
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <fcntl.h>
60 #include <string.h>
61 #include <sys/socket.h>
62 #include <sys/ioctl.h>
63 #include <net/if.h>
64 #include <netinet/in.h>
65 #include <linux/if_ether.h>
66 #include <netinet/if_ether.h>
67
68 #ifdef HAVE_NETPACKET_PACKET_H
69 #include <netpacket/packet.h>
70 #endif
71 #ifdef SO_ATTACH_FILTER
72 #include <linux/types.h>
73 #include <linux/filter.h>
74 #endif
75
76 #ifndef __GLIBC__
77 typedef int socklen_t;
78 #endif
79
80 #ifndef MSG_TRUNC
81 #define MSG_TRUNC 0
82 #endif
83
84 #define MAX_LINKHEADER_SIZE 256
85
86 /* Prototypes for internal functions */
87 static int map_arphrd_to_dlt( int arptype );
88 static int live_open_old( pcap_t *, char *, int, int, char * );
89 static int live_open_new( pcap_t *, char *, int, int, char * );
90 static int pcap_read_packet( pcap_t *, pcap_handler, u_char * );
91
92 /* Wrap some ioctl calls */
93 static int iface_get_id( int fd, const char *device, char *ebuf );
94 static int iface_get_mtu( int fd, const char *device, char *ebuf );
95 static int iface_get_arptype( int fd, const char *device, char *ebuf );
96 static int iface_bind( int fd, int ifindex, char *ebuf );
97 static int iface_bind_old( int fd, const char *device, char *ebuf );
98
99 /*
100 pcap_open_live:
101
102 Get a handle for a live capture from the given device. You can
103 pass NULL as device to get all packages (without link level
104 information of course). If you pass 1 as promisc the interface
105 will be set to promiscous mode (XXX: I think this usage should
106 be deprecated and functions be added to select that later allow
107 modification of that values -- Torsten).
108
109 See also pcap(3).
110 */
111 pcap_t *
112 pcap_open_live( char *device, int snaplen, int promisc, int to_ms, char *ebuf )
113 {
114 /* Allocate a handle for this session. */
115
116 pcap_t *handle = malloc(sizeof(*handle));
117 if( handle == NULL ) {
118 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
119 pcap_strerror(errno));
120 return NULL;
121 }
122
123 /* Initialize some components of the pcap structure. */
124
125 memset( handle, 0, sizeof(*handle) );
126 handle->snapshot = snaplen;
127 handle->md.timeout = to_ms;
128 handle->md.promisc = promisc;
129 handle->md.device = strdup( device );
130 if( handle->md.device == NULL ) {
131 snprintf(ebuf, PCAP_ERRBUF_SIZE, "strdup: %s",
132 pcap_strerror(errno) );
133 free( handle );
134 return NULL;
135 }
136
137 /* Current Linux kernels use the protocol family PF_PACKET to
138 * allow direct access to all packets on the network while
139 * older kernels had a special socket type SOCK_PACKET to
140 * implement this feature.
141 * While this old implementation is kind of obsolete we need
142 * to be compatible with older kernels for a while so we are
143 * trying both methods with the newer method preferred. */
144
145 if( ! (live_open_new(handle, device, promisc, to_ms, ebuf) ||
146 live_open_old(handle, device, promisc, to_ms, ebuf)) )
147 {
148 /* Both methods to open the packet socket failed. Tidy
149 * up and report our failure (ebuf is expected to be
150 * set by the functions above). */
151
152 free(handle->md.device);
153 free( handle );
154 return NULL;
155 }
156
157 /* Okay, now we have a packet stream open. Maybe we need to handle
158 * a timeout? In that case we set the filehandle to nonblocking
159 * so pcap_read can try reading the fd and call select if no data
160 * is available at once. */
161
162 if( to_ms > 0 ) {
163 int flags = fcntl( handle->fd, F_GETFL );
164 if( flags != -1 ) {
165 flags |= O_NONBLOCK;
166 flags = fcntl( handle->fd, F_SETFL, flags );
167 }
168 if( flags == -1 ) {
169 snprintf(ebuf, PCAP_ERRBUF_SIZE, "fcntl: %s",
170 pcap_strerror(errno));
171 pcap_close( handle );
172 return NULL;
173 }
174 }
175
176 return handle;
177 }
178
179 /*
180 pcap_read:
181
182 Read at most max_packets from the capture stream and
183 call the callback for each of them. Returns the number
184 of packets handled or -1 if an error occured.
185
186 XXX: Can I rely on the Linux-specified behaviour of select
187 (returning the time left in the timeval structure)? I really
188 don't want to query the system time before each select call...
189 */
190 int
191 pcap_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
192 {
193 int status, packets;
194 fd_set read_fds;
195 struct timeval tv;
196
197 if( handle->md.timeout > 0 ) {
198 tv.tv_usec = (handle->md.timeout % 1000) * 1000;
199 tv.tv_sec = (handle->md.timeout / 1000);
200 }
201
202 for( packets = 0; max_packets == -1 || packets < max_packets; )
203 {
204 status = pcap_read_packet( handle, callback, user );
205
206 if( status > 0 ) {
207 packets++;
208 continue;
209 } else if( status == -1 )
210 return -1;
211
212 /* paranoia - the recvmsg call should block if we don't use
213 * a timeout */
214 if( handle->md.timeout <= 0 )
215 continue;
216
217 /* No packet available - go to sleep */
218 FD_ZERO( &read_fds );
219 FD_SET( handle->fd, &read_fds );
220 status = select( handle->fd + 1,
221 &read_fds, NULL, NULL, &tv );
222 if( status == -1 ) {
223 snprintf(handle->errbuf, sizeof(handle->errbuf),
224 "select: %s", pcap_strerror(errno));
225 return -1;
226 } else if( status == 0 ||
227 (tv.tv_usec == 0 && tv.tv_sec == 0) )
228 return packets;
229 }
230
231 return packets;
232 }
233
234 /*
235 pcap_read_packet:
236
237 Read a packet from the socket calling the handler provided by
238 the user. Returns 0 if no packet was there, 1 if a packet was
239 handled and -1 if an error occured.
240 */
241 static int
242 pcap_read_packet( pcap_t *handle, pcap_handler callback, u_char *userdata )
243 {
244 struct sockaddr from;
245 socklen_t fromlen;
246 int packet_len, caplen;
247 struct pcap_pkthdr pcap_header;
248
249 /* We don't currently use the from return value of recvfrom but
250 * this will probably implemented in the future. */
251
252 /* Receive a single packet from the kernel */
253 do {
254 fromlen = sizeof(from);
255 packet_len = recvfrom(
256 handle->fd, handle->buffer + handle->offset,
257 handle->snapshot, MSG_TRUNC,
258 (struct sockaddr *) &from, &fromlen );
259 } while( packet_len == -1 && errno == EINTR );
260
261 /* Check if some error occured */
262 if( packet_len == -1 ) {
263 if( errno == EAGAIN )
264 return 0; /* no packet there */
265 else {
266 snprintf(handle->errbuf, sizeof(handle->errbuf),
267 "recvfrom: %s", pcap_strerror(errno));
268 return -1;
269 }
270 }
271
272 /* XXX: According to the kernel source we should get the real
273 * packet len if calling recvfrom with MSG_TRUNC set. It does
274 * not seem to work here :(, but it is supported by this code
275 * anyway. */
276
277 caplen = packet_len;
278 if( caplen > handle->snapshot )
279 caplen = handle->snapshot;
280
281 /* Run the packet filter if not using kernel filter */
282 if( !handle->md.use_bpf && handle->fcode.bf_insns ) {
283 if( bpf_filter(handle->fcode.bf_insns, handle->buffer,
284 packet_len, caplen) == 0 )
285 {
286 /* rejected by filter */
287 return 0;
288 }
289 }
290
291 /* Fill in our own header data */
292
293 if( ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1 ) {
294 snprintf(handle->errbuf, sizeof(handle->errbuf),
295 "ioctl: %s", pcap_strerror(errno));
296 return -1;
297 }
298 pcap_header.caplen = caplen;
299 pcap_header.len = packet_len;
300
301 /* Call the user supplied callback function */
302 handle->md.stat.ps_recv++;
303 callback( userdata, &pcap_header, handle->buffer + handle->offset);
304
305 return 1;
306 }
307
308 /*
309 pcap_stats:
310
311 Get the statistics for the given packet capture handle.
312 */
313 int
314 pcap_stats( pcap_t *handle, struct pcap_stat *stats )
315 {
316 *stats = handle->md.stat;
317 return 0;
318 }
319
320 /*
321 pcap_setfilter:
322
323 Attach the given BPF code to the packet capture device.
324 */
325 int
326 pcap_setfilter( pcap_t *handle, struct bpf_program *filter )
327 {
328 #ifdef SO_ATTACH_FILTER
329 struct sock_fprog fcode;
330 #endif
331
332 if( !handle )
333 return -1;
334 if( !filter ) {
335 strncpy(handle->errbuf, "setfilter: No filter specified",
336 sizeof(handle->errbuf));
337 return -1;
338 }
339
340 /* Free old filter code if existing */
341 handle->fcode.bf_len = 0;
342 if( handle->fcode.bf_insns ) {
343 free( handle->fcode.bf_insns );
344 handle->fcode.bf_insns = NULL;
345 }
346
347
348 /* Make our private copy of the filter */
349 handle->fcode.bf_len = filter->bf_len;
350 handle->fcode.bf_insns =
351 malloc( filter->bf_len * sizeof(*filter->bf_insns) );
352 if( handle->fcode.bf_insns == NULL ) {
353 snprintf(handle->errbuf, sizeof(handle->errbuf),
354 "malloc: %s", pcap_strerror(errno));
355 return -1;
356 }
357 memcpy( handle->fcode.bf_insns, filter->bf_insns,
358 filter->bf_len * sizeof(*filter->bf_insns) );
359
360 /* Run user level packet filter by default. Will be overriden if
361 * installing a kernel filter succeeds. */
362 handle->md.use_bpf = 0;
363
364 /* Install kernel level filter if possible */
365
366 #ifdef SO_ATTACH_FILTER
367 /* Oh joy, the Linux kernel uses struct sock_fprog instead of
368 * struct bpf_program and of course the length field is of
369 * different size. Pointed out by Sebastian */
370
371 fcode.filter = (struct sock_filter *) handle->fcode.bf_insns;
372 fcode.len = filter->bf_len;
373 #ifdef USHRT_MAX
374 if( filter->bf_len > USHRT_MAX ) {
375 fprintf( stderr, "Warning: Filter to complex for kernel\n" );
376 /* paranoid - should never happen */
377 }
378 else
379 #endif
380 if( setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
381 &fcode, sizeof(fcode)) == 0 )
382 {
383 handle->md.use_bpf = 1;
384 } else
385 {
386 /* Print a warning if kernel filter available but a problem
387 * occured using it. */
388 if( errno != ENOPROTOOPT && errno != EOPNOTSUPP ) {
389 fprintf( stderr, "Warning: Kernel filter failed: %s\n",
390 pcap_strerror(errno) );
391 }
392 }
393 #endif
394
395 return 0;
396 }
397
398
399 /*
400 map_arphrd_to_dlt:
401
402 Linux uses the ARP hardware type to identify the type of an
403 interface. pcap uses the DLT_xxx constants for this. This
404 function maps the ARPHRD_xxx constant to an appropriate
405 DLT_xxx constant.
406
407 Returns -1 if unable to map the type.
408 */
409 static int map_arphrd_to_dlt( int arptype )
410 {
411 switch( arptype ) {
412 case ARPHRD_ETHER:
413 case ARPHRD_METRICOM:
414 case ARPHRD_LOOPBACK: return DLT_EN10MB;
415 case ARPHRD_EETHER: return DLT_EN3MB;
416 case ARPHRD_AX25: return DLT_AX25;
417 case ARPHRD_PRONET: return DLT_PRONET;
418 case ARPHRD_CHAOS: return DLT_CHAOS;
419 case ARPHRD_IEEE802: return DLT_IEEE802;
420 case ARPHRD_ARCNET: return DLT_ARCNET;
421 case ARPHRD_FDDI: return DLT_FDDI;
422
423 case ARPHRD_PPP:
424 case ARPHRD_CSLIP:
425 case ARPHRD_SLIP6:
426 case ARPHRD_CSLIP6:
427 case ARPHRD_SLIP: return DLT_RAW;
428 }
429
430 return -1;
431 }
432
433 /* ===== Functions to interface to the newer kernels ================== */
434
435 /*
436 live_open_new:
437
438 Try to open a packet socket using the new kernel interface.
439 Returns 0 on failure.
440 FIXME: 0 uses to mean success (Sebastian)
441 */
442 static int
443 live_open_new( pcap_t *handle, char *device, int promisc,
444 int to_ms, char *ebuf )
445 {
446 #ifdef HAVE_NETPACKET_PACKET_H
447 int sock_fd = -1, device_id, mtu, arptype;
448 struct packet_mreq mr;
449
450 /* One shot loop used for error handling - bail out with break */
451
452 do {
453
454 /* Open a socket with protocol family packet. */
455 sock_fd = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );
456 if( sock_fd == -1 ) {
457 snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket: %s",
458 pcap_strerror(errno) );
459 break;
460 }
461
462 /* It seems the kernel supports the new interface. */
463 handle->md.sock_packet = 0;
464
465 /* Currently we only support monitoring a single interface.
466 * While the kernel can do more I want to reimplement the
467 * old features first before adding more. */
468
469 if( !device ) {
470 snprintf(ebuf, PCAP_ERRBUF_SIZE,
471 "pcap_open_live: No device given" );
472 break;
473 }
474
475 /* What kind of frames do we have to deal with? Fall back
476 * to cooked mode if we have an unknown interface type. */
477
478 arptype = iface_get_arptype(sock_fd, device, ebuf);
479 if( arptype == -1 )
480 break;
481 handle->linktype = map_arphrd_to_dlt( arptype );
482 if( handle->linktype == -1 ) {
483 /* Unknown interface type - reopen in cooked mode */
484
485 if( close(sock_fd) == -1 ) {
486 snprintf(ebuf, PCAP_ERRBUF_SIZE,
487 "close: %s", pcap_strerror(errno));
488 break;
489 }
490 sock_fd = socket( PF_PACKET, SOCK_DGRAM,
491 htons(ETH_P_ALL) );
492 if( sock_fd == -1 ) {
493 snprintf(ebuf, PCAP_ERRBUF_SIZE,
494 "socket: %s", pcap_strerror(errno));
495 break;
496 }
497
498 fprintf( stderr,
499 "Warning: Falling back to cooked socket\n" );
500 handle->linktype = DLT_RAW;
501 }
502
503
504 device_id = iface_get_id( sock_fd, device, ebuf );
505 if( device_id == -1 )
506 break;
507
508 if( iface_bind(sock_fd, device_id, ebuf) == -1 )
509 break;
510
511 /* Select promiscous mode on/off */
512
513 #ifdef SOL_PACKET
514 /* XXX: We got reports that this does not work in 2.3.99.
515 * Need to investigate. Using ioctl to switch the promisc
516 * mode at device level costs us most of the benefits of
517 * using the new kernel interface.
518 * UPDATE: I found the bug. The kernel checks mr_alen
519 * even if it is of zero interest for the request. A
520 * random value there made the kernel return EINVAL.
521 * Probably the right solution is to memset the whole
522 * struct at first. */
523
524 memset( &mr, 0, sizeof(mr) );
525 mr.mr_ifindex = device_id;
526 mr.mr_type = promisc ?
527 PACKET_MR_PROMISC : PACKET_MR_ALLMULTI;
528 if( setsockopt( sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
529 &mr, sizeof(mr) ) == -1 )
530 {
531 snprintf(ebuf, PCAP_ERRBUF_SIZE,
532 "setsockopt: %s", pcap_strerror(errno));
533 break;
534 }
535 #endif
536
537 /* Compute the buffersize */
538
539 mtu = iface_get_mtu(sock_fd, device, ebuf);
540 if( mtu == -1 )
541 break;
542 handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
543
544 /* Fill in the pcap structure */
545
546 handle->fd = sock_fd;
547 handle->offset = 0;
548
549 handle->buffer = malloc( handle->bufsize );
550 if( !handle->buffer ) {
551 snprintf(ebuf, PCAP_ERRBUF_SIZE,
552 "malloc: %s", pcap_strerror(errno));
553 break;
554 }
555
556 return 1;
557
558 } while(0);
559
560 if( sock_fd != -1 )
561 close( sock_fd );
562 return 0;
563 #else
564 strncpy(ebuf,
565 "New packet capturing interface not supported by build "
566 "environment", PCAP_ERRBUF_SIZE);
567 return 0;
568 #endif
569 }
570
571 #ifdef HAVE_NETPACKET_PACKET_H
572 /*
573 iface_get_id:
574
575 Return the index of the given device name. Fill ebuf and return
576 -1 on failure.
577 */
578 static int
579 iface_get_id( int fd, const char *device, char *ebuf )
580 {
581 struct ifreq ifr;
582
583 memset( &ifr, 0, sizeof(ifr) );
584 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
585
586 if( ioctl(fd, SIOCGIFINDEX, &ifr) == -1 ) {
587 snprintf(ebuf, PCAP_ERRBUF_SIZE,
588 "ioctl: %s", pcap_strerror(errno));
589 return -1;
590 }
591
592 return ifr.ifr_ifindex;
593 }
594
595 /*
596 iface_bind:
597
598 Bind the socket associated with FD to the given device.
599 */
600 static int
601 iface_bind( int fd, int ifindex, char *ebuf )
602 {
603 struct sockaddr_ll sll;
604
605 memset( &sll, 0, sizeof(sll) );
606 sll.sll_family = AF_PACKET;
607 sll.sll_ifindex = ifindex;
608 sll.sll_protocol = htons(ETH_P_ALL);
609
610 if( bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1 ) {
611 snprintf(ebuf, PCAP_ERRBUF_SIZE,
612 "bind: %s", pcap_strerror(errno));
613 return -1;
614 }
615
616 return 0;
617 }
618
619 #endif
620
621
622 /* ===== Functions to interface to the older kernels ================== */
623
624 /* With older kernels promiscuous mode is kind of interesting because we
625 * have to reset the interface before exiting. The problem can't really
626 * be solved without some daemon taking care of managing usage counts.
627 * We save the promiscuous state of the device when opening the capture
628 * stream and arrange for it to be reset on process exit.
629 *
630 * XXX: This solution is still not correct even for this case. The
631 * devices stay in promiscuous mode until the process exits. I need to
632 * modify pcap_close to solve this. */
633
634 struct ifreq restore_ifr;
635 /* Contains the device name and the interface flags to be restored
636 * at exit */
637
638 static void restore_interface( void )
639 {
640 int status = socket(PF_INET, SOCK_PACKET, 0);
641
642 if( status != -1 )
643 status = ioctl(status, SIOCSIFFLAGS, &restore_ifr);
644
645 if( status == -1 ) {
646 fprintf(stderr,
647 "Can't restore interface flags. Please adjust manually. \n"
648 "Hint: This can't happen with Linux >= 2.2.0.\n");
649 }
650 }
651
652 /*
653 live_open_old:
654
655 Try to open a packet socket using the old kernel interface.
656 Returns 0 on failure.
657 FIXME: 0 uses to mean success (Sebastian)
658 */
659 static int
660 live_open_old( pcap_t *handle, char *device, int promisc,
661 int to_ms, char *ebuf )
662 {
663 int sock_fd = -1, mtu, arptype;
664 struct ifreq ifr;
665
666 do {
667 /* Open the socket */
668
669 sock_fd = socket( PF_INET, SOCK_PACKET, htons(ETH_P_ALL) );
670 if( sock_fd == -1 ) {
671 snprintf(ebuf, PCAP_ERRBUF_SIZE,
672 "socket: %s", pcap_strerror(errno));
673 break;
674 }
675
676 /* It worked - we are using the old interface */
677 handle->md.sock_packet = 1;
678
679 /* Bind to the given device */
680
681 if( !device ) {
682 strncpy(ebuf, "pcap_open_live: No interface given",
683 PCAP_ERRBUF_SIZE);
684 break;
685 }
686 if( iface_bind_old(sock_fd, device, ebuf) == -1 )
687 break;
688
689 /* Go to promisc mode */
690 if( promisc ) {
691 memset( &ifr, 0, sizeof(ifr) );
692 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
693 if( ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1 ) {
694 snprintf(ebuf, PCAP_ERRBUF_SIZE,
695 "ioctl: %s", pcap_strerror(errno));
696 break;
697 }
698 if( (ifr.ifr_flags & IFF_PROMISC) == 0 ) {
699 restore_ifr = ifr;
700 ifr.ifr_flags |= IFF_PROMISC;
701 if( ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1 ) {
702 snprintf(ebuf, PCAP_ERRBUF_SIZE,
703 "ioctl: %s",
704 pcap_strerror(errno));
705 break;
706 }
707 if( atexit(restore_interface) == -1 ) {
708 restore_interface();
709 strncpy(ebuf, "atexit failed",
710 PCAP_ERRBUF_SIZE);
711 break;
712 }
713 }
714 }
715
716
717 /* Compute the buffersize */
718
719 mtu = iface_get_mtu(sock_fd, device, ebuf);
720 if( mtu == -1 )
721 break;
722 handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
723
724 /* All done - fill in the pcap handle */
725
726 arptype = iface_get_arptype(sock_fd, device, ebuf);
727 if( arptype == -1 )
728 break;
729
730 handle->fd = sock_fd;
731 handle->offset = 0;
732 handle->linktype = map_arphrd_to_dlt( arptype );
733 if( handle->linktype == -1 ) {
734 snprintf(ebuf, PCAP_ERRBUF_SIZE,
735 "interface type of %s not supported", device);
736 break;
737 }
738 handle->buffer = malloc( handle->bufsize );
739 if( !handle->buffer ) {
740 snprintf(ebuf, PCAP_ERRBUF_SIZE,
741 "malloc: %s", pcap_strerror(errno));
742 break;
743 }
744
745 return 1;
746
747 } while(0);
748
749 if( sock_fd != -1 )
750 close( sock_fd );
751 return 0;
752 }
753
754 /*
755 iface_bind_old:
756
757 Bind the socket associated with FD to the given device using the
758 interface of the old kernels.
759 */
760 static int
761 iface_bind_old( int fd, const char *device, char *ebuf )
762 {
763 struct sockaddr saddr;
764
765 memset( &saddr, 0, sizeof(saddr) );
766 strncpy( saddr.sa_data, device, sizeof(saddr.sa_data) );
767 if( bind(fd, &saddr, sizeof(saddr)) == -1 ) {
768 snprintf(ebuf, PCAP_ERRBUF_SIZE,
769 "bind: %s", pcap_strerror(errno));
770 return -1;
771 }
772
773 return 0;
774 }
775
776
777 /* ===== System calls available on all supported kernels ============== */
778
779 /*
780 iface_get_mtu:
781
782 Query the kernel for the MTU of the given interface.
783 */
784 static int
785 iface_get_mtu( int fd, const char *device, char *ebuf )
786 {
787 struct ifreq ifr;
788
789 memset( &ifr, 0, sizeof(ifr) );
790 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
791
792 if( ioctl(fd, SIOCGIFMTU, &ifr) == -1 ) {
793 snprintf(ebuf, PCAP_ERRBUF_SIZE,
794 "ioctl: %s", pcap_strerror(errno));
795 return -1;
796 }
797
798 return ifr.ifr_mtu;
799 }
800
801 /*
802 iface_get_arptype:
803
804 Get the hardware type of the given interface as ARPHRD_xxx constant.
805 */
806 static int
807 iface_get_arptype( int fd, const char *device, char *ebuf )
808 {
809 struct ifreq ifr;
810
811 memset( &ifr, 0, sizeof(ifr) );
812 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
813
814 if( ioctl(fd, SIOCGIFHWADDR, &ifr) == -1 ) {
815 snprintf(ebuf, PCAP_ERRBUF_SIZE,
816 "ioctl: %s", pcap_strerror(errno));
817 return -1;
818 }
819
820 return ifr.ifr_hwaddr.sa_family;
821 }
822