pcap-linux.c revision 39291
126175Sfenner/* 239291Sfenner * Copyright (c) 1996, 1997 326175Sfenner * The Regents of the University of California. All rights reserved. 426175Sfenner * 526175Sfenner * Redistribution and use in source and binary forms, with or without 626175Sfenner * modification, are permitted provided that: (1) source code distributions 726175Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 826175Sfenner * distributions including binary code include the above copyright notice and 926175Sfenner * this paragraph in its entirety in the documentation or other materials 1026175Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1126175Sfenner * features or use of this software display the following acknowledgement: 1226175Sfenner * ``This product includes software developed by the University of California, 1326175Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1426175Sfenner * the University nor the names of its contributors may be used to endorse 1526175Sfenner * or promote products derived from this software without specific prior 1626175Sfenner * written permission. 1726175Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1826175Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1926175Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2026175Sfenner */ 2126175Sfenner#ifndef lint 2226175Sfennerstatic const char rcsid[] = 2339291Sfenner "@(#) $Header: pcap-linux.c,v 1.15 97/10/02 22:39:37 leres Exp $ (LBL)"; 2426175Sfenner#endif 2526175Sfenner 2626175Sfenner#include <sys/param.h> 2726175Sfenner#include <sys/ioctl.h> 2826175Sfenner#include <sys/socket.h> 2926175Sfenner#include <sys/time.h> 3026175Sfenner 3126175Sfenner#include <net/if.h> 3239291Sfenner#ifdef HAVE_NET_IF_ARP_H 3339291Sfenner#include <net/if_arp.h> 3439291Sfenner#else 3539291Sfenner#include <linux/if_arp.h> 3639291Sfenner#endif 3739291Sfenner#include <linux/if_ether.h> 3826175Sfenner 3926175Sfenner#include <netinet/in.h> 4026175Sfenner 4126175Sfenner#include <errno.h> 4239291Sfenner#include <malloc.h> 4326175Sfenner#include <stdio.h> 4426175Sfenner#include <stdlib.h> 4526175Sfenner#include <string.h> 4626175Sfenner#include <unistd.h> 4726175Sfenner 4826175Sfennerstatic struct ifreq saved_ifr; 4926175Sfenner 5026175Sfenner#include "pcap-int.h" 5126175Sfenner 5226175Sfenner#include "gnuc.h" 5326175Sfenner#ifdef HAVE_OS_PROTO_H 5426175Sfenner#include "os-proto.h" 5526175Sfenner#endif 5626175Sfenner 5726175Sfennervoid linux_restore_ifr(void); 5826175Sfenner 5926175Sfennerint 6026175Sfennerpcap_stats(pcap_t *p, struct pcap_stat *ps) 6126175Sfenner{ 6226175Sfenner 6326175Sfenner *ps = p->md.stat; 6426175Sfenner return (0); 6526175Sfenner} 6626175Sfenner 6726175Sfennerint 6826175Sfennerpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 6926175Sfenner{ 7026175Sfenner register int cc; 7126175Sfenner register int bufsize; 7226175Sfenner register int caplen; 7326175Sfenner register u_char *bp; 7426175Sfenner struct sockaddr from; 7526175Sfenner int fromlen; 7626175Sfenner 7739291Sfenner bp = p->buffer + p->offset; 7826175Sfenner bufsize = p->bufsize; 7926175Sfenner if (p->md.pad > 0) { 8039291Sfenner memset(bp, 0, p->md.pad); 8126175Sfenner bp += p->md.pad; 8226175Sfenner bufsize -= p->md.pad; 8326175Sfenner } 8426175Sfenner 8526175Sfenneragain: 8626175Sfenner do { 8726175Sfenner fromlen = sizeof(from); 8826175Sfenner cc = recvfrom(p->fd, bp, bufsize, 0, &from, &fromlen); 8926175Sfenner if (cc < 0) { 9026175Sfenner /* Don't choke when we get ptraced */ 9126175Sfenner switch (errno) { 9226175Sfenner 9326175Sfenner case EINTR: 9426175Sfenner goto again; 9526175Sfenner 9626175Sfenner case EWOULDBLOCK: 9726175Sfenner return (0); /* XXX */ 9826175Sfenner } 9926175Sfenner sprintf(p->errbuf, "read: %s", pcap_strerror(errno)); 10026175Sfenner return (-1); 10126175Sfenner } 10226175Sfenner } while (strcmp(p->md.device, from.sa_data)); 10326175Sfenner 10426175Sfenner /* If we need have leading zero bytes, adjust count */ 10526175Sfenner cc += p->md.pad; 10639291Sfenner bp = p->buffer + p->offset; 10726175Sfenner 10826175Sfenner /* If we need to step over leading junk, adjust count and pointer */ 10926175Sfenner cc -= p->md.skip; 11026175Sfenner bp += p->md.skip; 11126175Sfenner 11226175Sfenner /* Captured length can't exceed our read buffer size */ 11326175Sfenner caplen = cc; 11426175Sfenner if (caplen > bufsize) 11526175Sfenner caplen = bufsize; 11626175Sfenner 11726175Sfenner /* Captured length can't exceed the snapshot length */ 11826175Sfenner if (caplen > p->snapshot) 11926175Sfenner caplen = p->snapshot; 12026175Sfenner 12126175Sfenner if (p->fcode.bf_insns == NULL || 12226175Sfenner bpf_filter(p->fcode.bf_insns, bp, cc, caplen)) { 12326175Sfenner struct pcap_pkthdr h; 12426175Sfenner 12526175Sfenner ++p->md.stat.ps_recv; 12626175Sfenner /* Get timestamp */ 12726175Sfenner if (ioctl(p->fd, SIOCGSTAMP, &h.ts) < 0) { 12826175Sfenner sprintf(p->errbuf, "SIOCGSTAMP: %s", 12926175Sfenner pcap_strerror(errno)); 13026175Sfenner return (-1); 13126175Sfenner } 13226175Sfenner h.len = cc; 13326175Sfenner h.caplen = caplen; 13426175Sfenner (*callback)(user, &h, bp); 13526175Sfenner return (1); 13626175Sfenner } 13726175Sfenner return (0); 13826175Sfenner} 13926175Sfenner 14026175Sfennerpcap_t * 14126175Sfennerpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 14226175Sfenner{ 14326175Sfenner register int fd, broadcast; 14426175Sfenner register pcap_t *p; 14526175Sfenner struct ifreq ifr; 14639291Sfenner struct sockaddr sa; 14726175Sfenner 14826175Sfenner p = (pcap_t *)malloc(sizeof(*p)); 14926175Sfenner if (p == NULL) { 15026175Sfenner sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 15126175Sfenner return (NULL); 15226175Sfenner } 15339291Sfenner memset(p, 0, sizeof(*p)); 15426175Sfenner fd = -1; 15526175Sfenner 15639291Sfenner fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); 15739291Sfenner if (fd < 0) { 15839291Sfenner sprintf(ebuf, "socket: %s", pcap_strerror(errno)); 15939291Sfenner goto bad; 16039291Sfenner } 16139291Sfenner p->fd = fd; 16239291Sfenner 16339291Sfenner /* Bind to the interface name */ 16439291Sfenner memset(&sa, 0, sizeof(sa)); 16539291Sfenner sa.sa_family = AF_INET; 16639291Sfenner (void)strncpy(sa.sa_data, device, sizeof(sa.sa_data)); 16739291Sfenner if (bind(p->fd, &sa, sizeof(sa))) { 16839291Sfenner sprintf(ebuf, "bind: %s: %s", device, pcap_strerror(errno)); 16939291Sfenner goto bad; 17039291Sfenner } 17139291Sfenner 17239291Sfenner memset(&ifr, 0, sizeof(ifr)); 17339291Sfenner strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 17439291Sfenner if (ioctl(p->fd, SIOCGIFHWADDR, &ifr) < 0 ) { 17539291Sfenner sprintf(ebuf, "SIOCGIFHWADDR: %s", pcap_strerror(errno)); 17639291Sfenner goto bad; 17739291Sfenner } 17826175Sfenner broadcast = 0; 17939291Sfenner switch (ifr.ifr_hwaddr.sa_family) { 18039291Sfenner 18139291Sfenner case ARPHRD_ETHER: 18239291Sfenner case ARPHRD_METRICOM: 18326175Sfenner p->linktype = DLT_EN10MB; 18439291Sfenner p->offset = 2; 18526175Sfenner ++broadcast; 18639291Sfenner break; 18739291Sfenner 18839291Sfenner case ARPHRD_EETHER: 18939291Sfenner p->linktype = DLT_EN3MB; 19039291Sfenner ++broadcast; 19139291Sfenner break; 19239291Sfenner 19339291Sfenner case ARPHRD_AX25: 19439291Sfenner p->linktype = DLT_AX25; 19539291Sfenner ++broadcast; 19639291Sfenner break; 19739291Sfenner 19839291Sfenner case ARPHRD_PRONET: 19939291Sfenner p->linktype = DLT_PRONET; 20039291Sfenner break; 20139291Sfenner 20239291Sfenner case ARPHRD_CHAOS: 20339291Sfenner p->linktype = DLT_CHAOS; 20439291Sfenner break; 20539291Sfenner 20639291Sfenner case ARPHRD_IEEE802: 20739291Sfenner p->linktype = DLT_IEEE802; 20839291Sfenner ++broadcast; 20939291Sfenner break; 21039291Sfenner 21139291Sfenner case ARPHRD_ARCNET: 21239291Sfenner p->linktype = DLT_ARCNET; 21339291Sfenner ++broadcast; 21439291Sfenner break; 21539291Sfenner 21639291Sfenner case ARPHRD_SLIP: 21739291Sfenner case ARPHRD_CSLIP: 21839291Sfenner case ARPHRD_SLIP6: 21939291Sfenner case ARPHRD_CSLIP6: 22039291Sfenner case ARPHRD_PPP: 22139291Sfenner p->linktype = DLT_RAW; 22239291Sfenner break; 22339291Sfenner 22439291Sfenner case ARPHRD_LOOPBACK: 22526175Sfenner p->linktype = DLT_NULL; 22626175Sfenner p->md.pad = 2; 22726175Sfenner p->md.skip = 12; 22839291Sfenner break; 22939291Sfenner 23039291Sfenner#ifdef ARPHRD_FDDI 23139291Sfenner /* Not all versions of the kernel has this define */ 23239291Sfenner case ARPHRD_FDDI: 23339291Sfenner p->linktype = DLT_FDDI; 23439291Sfenner ++broadcast; 23539291Sfenner break; 23639291Sfenner#endif 23739291Sfenner 23839291Sfenner#ifdef notdef 23939291Sfenner case ARPHRD_LOCALTLK: 24039291Sfenner case ARPHRD_NETROM: 24139291Sfenner case ARPHRD_APPLETLK: 24239291Sfenner case ARPHRD_DLCI: 24339291Sfenner case ARPHRD_RSRVD: 24439291Sfenner case ARPHRD_ADAPT: 24539291Sfenner case ARPHRD_TUNNEL: 24639291Sfenner case ARPHRD_TUNNEL6: 24739291Sfenner case ARPHRD_FRAD: 24839291Sfenner case ARPHRD_SKIP: 24939291Sfenner /* XXX currently do not know what to do with these... */ 25039291Sfenner abort(); 25139291Sfenner#endif 25239291Sfenner 25339291Sfenner default: 25439291Sfenner sprintf(ebuf, "unknown physical layer type 0x%x", 25539291Sfenner ifr.ifr_hwaddr.sa_family); 25626175Sfenner goto bad; 25726175Sfenner } 25826175Sfenner 25939291Sfenner /* Base the buffer size on the interface MTU */ 26039291Sfenner memset(&ifr, 0, sizeof(ifr)); 26139291Sfenner strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 26239291Sfenner if (ioctl(p->fd, SIOCGIFMTU, &ifr) < 0 ) { 26339291Sfenner sprintf(ebuf, "SIOCGIFMTU: %s", pcap_strerror(errno)); 26426175Sfenner goto bad; 26526175Sfenner } 26626175Sfenner 26739291Sfenner /* Leave room for link header (which is never large under linux...) */ 26839291Sfenner p->bufsize = ifr.ifr_mtu + 64; 26926175Sfenner 27039291Sfenner p->buffer = (u_char *)malloc(p->bufsize + p->offset); 27126175Sfenner if (p->buffer == NULL) { 27226175Sfenner sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 27326175Sfenner goto bad; 27426175Sfenner } 27526175Sfenner 27626175Sfenner /* XXX */ 27726175Sfenner if (promisc && broadcast) { 27826175Sfenner memset(&ifr, 0, sizeof(ifr)); 27926175Sfenner strcpy(ifr.ifr_name, device); 28026175Sfenner if (ioctl(p->fd, SIOCGIFFLAGS, &ifr) < 0 ) { 28126175Sfenner sprintf(ebuf, "SIOCGIFFLAGS: %s", pcap_strerror(errno)); 28226175Sfenner goto bad; 28326175Sfenner } 28426175Sfenner saved_ifr = ifr; 28526175Sfenner ifr.ifr_flags |= IFF_PROMISC; 28626175Sfenner if (ioctl(p->fd, SIOCSIFFLAGS, &ifr) < 0 ) { 28726175Sfenner sprintf(ebuf, "SIOCSIFFLAGS: %s", pcap_strerror(errno)); 28826175Sfenner goto bad; 28926175Sfenner } 29026175Sfenner ifr.ifr_flags &= ~IFF_PROMISC; 29126175Sfenner atexit(linux_restore_ifr); 29226175Sfenner } 29326175Sfenner 29426175Sfenner p->md.device = strdup(device); 29526175Sfenner if (p->md.device == NULL) { 29626175Sfenner sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 29726175Sfenner goto bad; 29826175Sfenner } 29926175Sfenner p->snapshot = snaplen; 30026175Sfenner 30126175Sfenner return (p); 30226175Sfennerbad: 30326175Sfenner if (fd >= 0) 30426175Sfenner (void)close(fd); 30526175Sfenner if (p->buffer != NULL) 30626175Sfenner free(p->buffer); 30726175Sfenner if (p->md.device != NULL) 30826175Sfenner free(p->md.device); 30926175Sfenner free(p); 31026175Sfenner return (NULL); 31126175Sfenner} 31226175Sfenner 31326175Sfennerint 31426175Sfennerpcap_setfilter(pcap_t *p, struct bpf_program *fp) 31526175Sfenner{ 31626175Sfenner 31726175Sfenner p->fcode = *fp; 31826175Sfenner return (0); 31926175Sfenner} 32026175Sfenner 32126175Sfennervoid 32226175Sfennerlinux_restore_ifr(void) 32326175Sfenner{ 32426175Sfenner register int fd; 32526175Sfenner 32626175Sfenner fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); 32726175Sfenner if (fd < 0) 32826175Sfenner fprintf(stderr, "linux socket: %s", pcap_strerror(errno)); 32926175Sfenner else if (ioctl(fd, SIOCSIFFLAGS, &saved_ifr) < 0) 33026175Sfenner fprintf(stderr, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno)); 33126175Sfenner} 332