]> The Tcpdump Group git mirrors - libpcap/blob - pcap-linux.c
c5f1d7928f9053991b0b934b7af2707aab960c82
[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 if( filter->bf_len > USHRT_MAX ) {
374 fprintf( stderr, "Warning: Filter to complex for kernel\n" );
375 /* paranoid - should never happen */
376 }
377 else if( setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
378 &fcode, sizeof(fcode)) == 0 )
379 {
380 handle->md.use_bpf = 1;
381 } else
382 {
383 /* Print a warning if kernel filter available but a problem
384 * occured using it. */
385 if( errno != ENOPROTOOPT && errno != EOPNOTSUPP ) {
386 fprintf( stderr, "Warning: Kernel filter failed: %s\n",
387 pcap_strerror(errno) );
388 }
389 }
390 #endif
391
392 return 0;
393 }
394
395
396 /*
397 map_arphrd_to_dlt:
398
399 Linux uses the ARP hardware type to identify the type of an
400 interface. pcap uses the DLT_xxx constants for this. This
401 function maps the ARPHRD_xxx constant to an appropriate
402 DLT_xxx constant.
403
404 Returns -1 if unable to map the type.
405 */
406 static int map_arphrd_to_dlt( int arptype )
407 {
408 switch( arptype ) {
409 case ARPHRD_ETHER:
410 case ARPHRD_METRICOM:
411 case ARPHRD_LOOPBACK: return DLT_EN10MB;
412 case ARPHRD_EETHER: return DLT_EN3MB;
413 case ARPHRD_AX25: return DLT_AX25;
414 case ARPHRD_PRONET: return DLT_PRONET;
415 case ARPHRD_CHAOS: return DLT_CHAOS;
416 case ARPHRD_IEEE802: return DLT_IEEE802;
417 case ARPHRD_ARCNET: return DLT_ARCNET;
418 case ARPHRD_FDDI: return DLT_FDDI;
419
420 case ARPHRD_PPP:
421 case ARPHRD_CSLIP:
422 case ARPHRD_SLIP6:
423 case ARPHRD_CSLIP6:
424 case ARPHRD_SLIP: return DLT_RAW;
425 }
426
427 return -1;
428 }
429
430 /* ===== Functions to interface to the newer kernels ================== */
431
432 /*
433 live_open_new:
434
435 Try to open a packet socket using the new kernel interface.
436 Returns 0 on failure.
437 FIXME: 0 uses to mean success (Sebastian)
438 */
439 static int
440 live_open_new( pcap_t *handle, char *device, int promisc,
441 int to_ms, char *ebuf )
442 {
443 #ifdef HAVE_NETPACKET_PACKET_H
444 int sock_fd = -1, device_id, mtu, arptype;
445 struct packet_mreq mr;
446
447 /* One shot loop used for error handling - bail out with break */
448
449 do {
450
451 /* Open a socket with protocol family packet. */
452 sock_fd = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );
453 if( sock_fd == -1 ) {
454 snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket: %s",
455 pcap_strerror(errno) );
456 break;
457 }
458
459 /* It seems the kernel supports the new interface. */
460 handle->md.sock_packet = 0;
461
462 /* Currently we only support monitoring a single interface.
463 * While the kernel can do more I want to reimplement the
464 * old features first before adding more. */
465
466 if( !device ) {
467 snprintf(ebuf, PCAP_ERRBUF_SIZE,
468 "pcap_open_live: No device given" );
469 break;
470 }
471
472 /* What kind of frames do we have to deal with? Fall back
473 * to cooked mode if we have an unknown interface type. */
474
475 arptype = iface_get_arptype(sock_fd, device, ebuf);
476 if( arptype == -1 )
477 break;
478 handle->linktype = map_arphrd_to_dlt( arptype );
479 if( handle->linktype == -1 ) {
480 /* Unknown interface type - reopen in cooked mode */
481
482 if( close(sock_fd) == -1 ) {
483 snprintf(ebuf, PCAP_ERRBUF_SIZE,
484 "close: %s", pcap_strerror(errno));
485 break;
486 }
487 sock_fd = socket( PF_PACKET, SOCK_DGRAM,
488 htons(ETH_P_ALL) );
489 if( sock_fd == -1 ) {
490 snprintf(ebuf, PCAP_ERRBUF_SIZE,
491 "socket: %s", pcap_strerror(errno));
492 break;
493 }
494
495 fprintf( stderr,
496 "Warning: Falling back to cooked socket\n" );
497 handle->linktype = DLT_RAW;
498 }
499
500
501 device_id = iface_get_id( sock_fd, device, ebuf );
502 if( device_id == -1 )
503 break;
504
505 if( iface_bind(sock_fd, device_id, ebuf) == -1 )
506 break;
507
508 /* Select promiscous mode on/off */
509
510 /* XXX: We got reports that this does not work in 2.3.99.
511 * Need to investigate. Using ioctl to switch the promisc
512 * mode at device level costs us most of the benefits of
513 * using the new kernel interface.
514 * UPDATE: I found the bug. The kernel checks mr_alen
515 * even if it is of zero interest for the request. A
516 * random value there made the kernel return EINVAL.
517 * Probably the right solution is to memset the whole
518 * struct at first. */
519
520 memset( &mr, 0, sizeof(mr) );
521 mr.mr_ifindex = device_id;
522 mr.mr_type = promisc ?
523 PACKET_MR_PROMISC : PACKET_MR_ALLMULTI;
524 if( setsockopt( sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
525 &mr, sizeof(mr) ) == -1 )
526 {
527 snprintf(ebuf, PCAP_ERRBUF_SIZE,
528 "setsockopt: %s", pcap_strerror(errno));
529 break;
530 }
531
532 /* Compute the buffersize */
533
534 mtu = iface_get_mtu(sock_fd, device, ebuf);
535 if( mtu == -1 )
536 break;
537 handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
538
539 /* Fill in the pcap structure */
540
541 handle->fd = sock_fd;
542 handle->offset = 0;
543
544 handle->buffer = malloc( handle->bufsize );
545 if( !handle->buffer ) {
546 snprintf(ebuf, PCAP_ERRBUF_SIZE,
547 "malloc: %s", pcap_strerror(errno));
548 break;
549 }
550
551 return 1;
552
553 } while(0);
554
555 if( sock_fd != -1 )
556 close( sock_fd );
557 return 0;
558 #else
559 strncpy(ebuf,
560 "New packet capturing interface not supported by build "
561 "environment", PCAP_ERRBUF_SIZE);
562 return 0;
563 #endif
564 }
565
566 #ifdef HAVE_NETPACKET_PACKET_H
567 /*
568 iface_get_id:
569
570 Return the index of the given device name. Fill ebuf and return
571 -1 on failure.
572 */
573 static int
574 iface_get_id( int fd, const char *device, char *ebuf )
575 {
576 struct ifreq ifr;
577
578 memset( &ifr, 0, sizeof(ifr) );
579 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
580
581 if( ioctl(fd, SIOCGIFINDEX, &ifr) == -1 ) {
582 snprintf(ebuf, PCAP_ERRBUF_SIZE,
583 "ioctl: %s", pcap_strerror(errno));
584 return -1;
585 }
586
587 return ifr.ifr_ifindex;
588 }
589
590 /*
591 iface_bind:
592
593 Bind the socket associated with FD to the given device.
594 */
595 static int
596 iface_bind( int fd, int ifindex, char *ebuf )
597 {
598 struct sockaddr_ll sll;
599
600 memset( &sll, 0, sizeof(sll) );
601 sll.sll_family = AF_PACKET;
602 sll.sll_ifindex = ifindex;
603 sll.sll_protocol = htons(ETH_P_ALL);
604
605 if( bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1 ) {
606 snprintf(ebuf, PCAP_ERRBUF_SIZE,
607 "bind: %s", pcap_strerror(errno));
608 return -1;
609 }
610
611 return 0;
612 }
613
614 #endif
615
616
617 /* ===== Functions to interface to the older kernels ================== */
618
619 /* With older kernels promiscuous mode is kind of interesting because we
620 * have to reset the interface before exiting. The problem can't really
621 * be solved without some daemon taking care of managing usage counts.
622 * We save the promiscuous state of the device when opening the capture
623 * stream and arrange for it to be reset on process exit.
624 *
625 * XXX: This solution is still not correct even for this case. The
626 * devices stay in promiscuous mode until the process exits. I need to
627 * modify pcap_close to solve this. */
628
629 struct ifreq restore_ifr;
630 /* Contains the device name and the interface flags to be restored
631 * at exit */
632
633 static void restore_interface( void )
634 {
635 int status = socket(PF_INET, SOCK_PACKET, 0);
636
637 if( status != -1 )
638 status = ioctl(status, SIOCSIFFLAGS, &restore_ifr);
639
640 if( status == -1 ) {
641 fprintf(stderr,
642 "Can't restore interface flags. Please adjust manually. \n"
643 "Hint: This can't happen with Linux >= 2.2.0.\n");
644 }
645 }
646
647 /*
648 live_open_old:
649
650 Try to open a packet socket using the old kernel interface.
651 Returns 0 on failure.
652 FIXME: 0 uses to mean success (Sebastian)
653 */
654 static int
655 live_open_old( pcap_t *handle, char *device, int promisc,
656 int to_ms, char *ebuf )
657 {
658 int sock_fd = -1, mtu, arptype;
659 struct ifreq ifr;
660
661 do {
662 /* Open the socket */
663
664 sock_fd = socket( PF_INET, SOCK_PACKET, htons(ETH_P_ALL) );
665 if( sock_fd == -1 ) {
666 snprintf(ebuf, PCAP_ERRBUF_SIZE,
667 "socket: %s", pcap_strerror(errno));
668 break;
669 }
670
671 /* It worked - we are using the old interface */
672 handle->md.sock_packet = 1;
673
674 /* Bind to the given device */
675
676 if( !device ) {
677 strncpy(ebuf, "pcap_open_live: No interface given",
678 PCAP_ERRBUF_SIZE);
679 break;
680 }
681 if( iface_bind_old(sock_fd, device, ebuf) == -1 )
682 break;
683
684 /* Go to promisc mode */
685 if( promisc ) {
686 memset( &ifr, 0, sizeof(ifr) );
687 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
688 if( ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1 ) {
689 snprintf(ebuf, PCAP_ERRBUF_SIZE,
690 "ioctl: %s", pcap_strerror(errno));
691 break;
692 }
693 if( (ifr.ifr_flags & IFF_PROMISC) == 0 ) {
694 restore_ifr = ifr;
695 ifr.ifr_flags |= IFF_PROMISC;
696 if( ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1 ) {
697 snprintf(ebuf, PCAP_ERRBUF_SIZE,
698 "ioctl: %s",
699 pcap_strerror(errno));
700 break;
701 }
702 if( atexit(restore_interface) == -1 ) {
703 restore_interface();
704 strncpy(ebuf, "atexit failed",
705 PCAP_ERRBUF_SIZE);
706 break;
707 }
708 }
709 }
710
711
712 /* Compute the buffersize */
713
714 mtu = iface_get_mtu(sock_fd, device, ebuf);
715 if( mtu == -1 )
716 break;
717 handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
718
719 /* All done - fill in the pcap handle */
720
721 arptype = iface_get_arptype(sock_fd, device, ebuf);
722 if( arptype == -1 )
723 break;
724
725 handle->fd = sock_fd;
726 handle->offset = 0;
727 handle->linktype = map_arphrd_to_dlt( arptype );
728 if( handle->linktype == -1 ) {
729 snprintf(ebuf, PCAP_ERRBUF_SIZE,
730 "interface type of %s not supported", device);
731 break;
732 }
733 handle->buffer = malloc( handle->bufsize );
734 if( !handle->buffer ) {
735 snprintf(ebuf, PCAP_ERRBUF_SIZE,
736 "malloc: %s", pcap_strerror(errno));
737 break;
738 }
739
740 return 1;
741
742 } while(0);
743
744 if( sock_fd != -1 )
745 close( sock_fd );
746 return 0;
747 }
748
749 /*
750 iface_bind_old:
751
752 Bind the socket associated with FD to the given device using the
753 interface of the old kernels.
754 */
755 static int
756 iface_bind_old( int fd, const char *device, char *ebuf )
757 {
758 struct sockaddr saddr;
759
760 memset( &saddr, 0, sizeof(saddr) );
761 strncpy( saddr.sa_data, device, sizeof(saddr.sa_data) );
762 if( bind(fd, &saddr, sizeof(saddr)) == -1 ) {
763 snprintf(ebuf, PCAP_ERRBUF_SIZE,
764 "bind: %s", pcap_strerror(errno));
765 return -1;
766 }
767
768 return 0;
769 }
770
771
772 /* ===== System calls available on all supported kernels ============== */
773
774 /*
775 iface_get_mtu:
776
777 Query the kernel for the MTU of the given interface.
778 */
779 static int
780 iface_get_mtu( int fd, const char *device, char *ebuf )
781 {
782 struct ifreq ifr;
783
784 memset( &ifr, 0, sizeof(ifr) );
785 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
786
787 if( ioctl(fd, SIOCGIFMTU, &ifr) == -1 ) {
788 snprintf(ebuf, PCAP_ERRBUF_SIZE,
789 "ioctl: %s", pcap_strerror(errno));
790 return -1;
791 }
792
793 return ifr.ifr_mtu;
794 }
795
796 /*
797 iface_get_arptype:
798
799 Get the hardware type of the given interface as ARPHRD_xxx constant.
800 */
801 static int
802 iface_get_arptype( int fd, const char *device, char *ebuf )
803 {
804 struct ifreq ifr;
805
806 memset( &ifr, 0, sizeof(ifr) );
807 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
808
809 if( ioctl(fd, SIOCGIFHWADDR, &ifr) == -1 ) {
810 snprintf(ebuf, PCAP_ERRBUF_SIZE,
811 "ioctl: %s", pcap_strerror(errno));
812 return -1;
813 }
814
815 return ifr.ifr_hwaddr.sa_family;
816 }
817