pcap-linux.c revision 26175
126175Sfenner/* 226175Sfenner * Copyright (c) 1996 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[] = 2326175Sfenner "@(#) $Header: pcap-linux.c,v 1.4 96/12/10 23:15:00 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> 3226175Sfenner 3326175Sfenner#include <netinet/in.h> 3426175Sfenner 3526175Sfenner#include <errno.h> 3626175Sfenner#include <stdio.h> 3726175Sfenner#include <stdlib.h> 3826175Sfenner#include <string.h> 3926175Sfenner#include <unistd.h> 4026175Sfenner 4126175Sfennerstatic struct ifreq saved_ifr; 4226175Sfenner 4326175Sfenner#include "pcap-int.h" 4426175Sfenner 4526175Sfenner#include "gnuc.h" 4626175Sfenner#ifdef HAVE_OS_PROTO_H 4726175Sfenner#include "os-proto.h" 4826175Sfenner#endif 4926175Sfenner 5026175Sfennervoid linux_restore_ifr(void); 5126175Sfenner 5226175Sfennerint 5326175Sfennerpcap_stats(pcap_t *p, struct pcap_stat *ps) 5426175Sfenner{ 5526175Sfenner 5626175Sfenner *ps = p->md.stat; 5726175Sfenner return (0); 5826175Sfenner} 5926175Sfenner 6026175Sfennerint 6126175Sfennerpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 6226175Sfenner{ 6326175Sfenner register int cc; 6426175Sfenner register int bufsize; 6526175Sfenner register int caplen; 6626175Sfenner register u_char *bp; 6726175Sfenner struct sockaddr from; 6826175Sfenner int fromlen; 6926175Sfenner 7026175Sfenner bp = (char *)p->buffer; 7126175Sfenner bufsize = p->bufsize; 7226175Sfenner if (p->md.pad > 0) { 7326175Sfenner bp += p->md.pad; 7426175Sfenner bufsize -= p->md.pad; 7526175Sfenner memset(p->buffer, 0, p->md.pad); 7626175Sfenner } 7726175Sfenner 7826175Sfenneragain: 7926175Sfenner do { 8026175Sfenner fromlen = sizeof(from); 8126175Sfenner cc = recvfrom(p->fd, bp, bufsize, 0, &from, &fromlen); 8226175Sfenner if (cc < 0) { 8326175Sfenner /* Don't choke when we get ptraced */ 8426175Sfenner switch (errno) { 8526175Sfenner 8626175Sfenner case EINTR: 8726175Sfenner goto again; 8826175Sfenner 8926175Sfenner case EWOULDBLOCK: 9026175Sfenner return (0); /* XXX */ 9126175Sfenner } 9226175Sfenner sprintf(p->errbuf, "read: %s", pcap_strerror(errno)); 9326175Sfenner return (-1); 9426175Sfenner } 9526175Sfenner } while (strcmp(p->md.device, from.sa_data)); 9626175Sfenner 9726175Sfenner /* If we need have leading zero bytes, adjust count */ 9826175Sfenner cc += p->md.pad; 9926175Sfenner bp = p->buffer; 10026175Sfenner 10126175Sfenner /* If we need to step over leading junk, adjust count and pointer */ 10226175Sfenner cc -= p->md.skip; 10326175Sfenner bp += p->md.skip; 10426175Sfenner 10526175Sfenner /* Captured length can't exceed our read buffer size */ 10626175Sfenner caplen = cc; 10726175Sfenner if (caplen > bufsize) 10826175Sfenner caplen = bufsize; 10926175Sfenner 11026175Sfenner /* Captured length can't exceed the snapshot length */ 11126175Sfenner if (caplen > p->snapshot) 11226175Sfenner caplen = p->snapshot; 11326175Sfenner 11426175Sfenner if (p->fcode.bf_insns == NULL || 11526175Sfenner bpf_filter(p->fcode.bf_insns, bp, cc, caplen)) { 11626175Sfenner struct pcap_pkthdr h; 11726175Sfenner 11826175Sfenner ++p->md.stat.ps_recv; 11926175Sfenner /* Get timestamp */ 12026175Sfenner if (ioctl(p->fd, SIOCGSTAMP, &h.ts) < 0) { 12126175Sfenner sprintf(p->errbuf, "SIOCGSTAMP: %s", 12226175Sfenner pcap_strerror(errno)); 12326175Sfenner return (-1); 12426175Sfenner } 12526175Sfenner h.len = cc; 12626175Sfenner h.caplen = caplen; 12726175Sfenner (*callback)(user, &h, bp); 12826175Sfenner return (1); 12926175Sfenner } 13026175Sfenner return (0); 13126175Sfenner} 13226175Sfenner 13326175Sfennerpcap_t * 13426175Sfennerpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 13526175Sfenner{ 13626175Sfenner register int fd, broadcast; 13726175Sfenner register pcap_t *p; 13826175Sfenner struct ifreq ifr; 13926175Sfenner 14026175Sfenner p = (pcap_t *)malloc(sizeof(*p)); 14126175Sfenner if (p == NULL) { 14226175Sfenner sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 14326175Sfenner return (NULL); 14426175Sfenner } 14526175Sfenner memset((char *)p, 0, sizeof(*p)); 14626175Sfenner fd = -1; 14726175Sfenner 14826175Sfenner /* XXX hack - map device name to link layer type */ 14926175Sfenner broadcast = 0; 15026175Sfenner if (strncmp("eth", device, 3) == 0) { 15126175Sfenner p->linktype = DLT_EN10MB; 15226175Sfenner ++broadcast; 15326175Sfenner } else if (strncmp("sl", device, 2) == 0) { 15426175Sfenner p->linktype = DLT_SLIP; 15526175Sfenner p->md.pad = 16; 15626175Sfenner } else if (strncmp("ppp", device, 3) == 0) { 15726175Sfenner p->linktype = DLT_PPP; 15826175Sfenner p->md.pad = 4; 15926175Sfenner } else if (strncmp("lo", device, 2) == 0) { 16026175Sfenner p->linktype = DLT_NULL; 16126175Sfenner p->md.pad = 2; 16226175Sfenner p->md.skip = 12; 16326175Sfenner } else { 16426175Sfenner sprintf(ebuf, "linux: unknown physical layer type"); 16526175Sfenner goto bad; 16626175Sfenner } 16726175Sfenner 16826175Sfenner /* Linux is full of magic numbers */ 16926175Sfenner fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); 17026175Sfenner if (fd < 0) { 17126175Sfenner sprintf(ebuf, "linux socket: %s", pcap_strerror(errno)); 17226175Sfenner goto bad; 17326175Sfenner } 17426175Sfenner p->fd = fd; 17526175Sfenner 17626175Sfenner 17726175Sfenner p->bufsize = 4096; /* XXX */ 17826175Sfenner p->buffer = (u_char *)malloc(p->bufsize); 17926175Sfenner if (p->buffer == NULL) { 18026175Sfenner sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 18126175Sfenner goto bad; 18226175Sfenner } 18326175Sfenner 18426175Sfenner /* XXX */ 18526175Sfenner if (promisc && broadcast) { 18626175Sfenner memset(&ifr, 0, sizeof(ifr)); 18726175Sfenner strcpy(ifr.ifr_name, device); 18826175Sfenner if (ioctl(p->fd, SIOCGIFFLAGS, &ifr) < 0 ) { 18926175Sfenner sprintf(ebuf, "SIOCGIFFLAGS: %s", pcap_strerror(errno)); 19026175Sfenner goto bad; 19126175Sfenner } 19226175Sfenner saved_ifr = ifr; 19326175Sfenner ifr.ifr_flags |= IFF_PROMISC; 19426175Sfenner if (ioctl(p->fd, SIOCSIFFLAGS, &ifr) < 0 ) { 19526175Sfenner sprintf(ebuf, "SIOCSIFFLAGS: %s", pcap_strerror(errno)); 19626175Sfenner goto bad; 19726175Sfenner } 19826175Sfenner ifr.ifr_flags &= ~IFF_PROMISC; 19926175Sfenner atexit(linux_restore_ifr); 20026175Sfenner } 20126175Sfenner 20226175Sfenner p->md.device = strdup(device); 20326175Sfenner if (p->md.device == NULL) { 20426175Sfenner sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 20526175Sfenner goto bad; 20626175Sfenner } 20726175Sfenner p->snapshot = snaplen; 20826175Sfenner 20926175Sfenner return (p); 21026175Sfennerbad: 21126175Sfenner if (fd >= 0) 21226175Sfenner (void)close(fd); 21326175Sfenner if (p->buffer != NULL) 21426175Sfenner free(p->buffer); 21526175Sfenner if (p->md.device != NULL) 21626175Sfenner free(p->md.device); 21726175Sfenner free(p); 21826175Sfenner return (NULL); 21926175Sfenner} 22026175Sfenner 22126175Sfennerint 22226175Sfennerpcap_setfilter(pcap_t *p, struct bpf_program *fp) 22326175Sfenner{ 22426175Sfenner 22526175Sfenner p->fcode = *fp; 22626175Sfenner return (0); 22726175Sfenner} 22826175Sfenner 22926175Sfennervoid 23026175Sfennerlinux_restore_ifr(void) 23126175Sfenner{ 23226175Sfenner register int fd; 23326175Sfenner 23426175Sfenner fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); 23526175Sfenner if (fd < 0) 23626175Sfenner fprintf(stderr, "linux socket: %s", pcap_strerror(errno)); 23726175Sfenner else if (ioctl(fd, SIOCSIFFLAGS, &saved_ifr) < 0) 23826175Sfenner fprintf(stderr, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno)); 23926175Sfenner} 240