1 /* 2 * Copyright (c) 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 #ifndef lint 22 static const char rcsid[] = 23 "@(#) $Header: pcap-linux.c,v 1.4 96/12/10 23:15:00 leres Exp $ (LBL)"; 24 #endif 25 26 #include <sys/param.h> 27 #include <sys/ioctl.h> 28 #include <sys/socket.h> 29 #include <sys/time.h> 30 31 #include <net/if.h> 32 33 #include <netinet/in.h> 34 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 static struct ifreq saved_ifr; 42 43 #include "pcap-int.h" 44 45 #include "gnuc.h" 46 #ifdef HAVE_OS_PROTO_H 47 #include "os-proto.h" 48 #endif 49 50 void linux_restore_ifr(void); 51 52 int 53 pcap_stats(pcap_t *p, struct pcap_stat *ps) 54 { 55 56 *ps = p->md.stat; 57 return (0); 58 } 59 60 int 61 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 62 { 63 register int cc; 64 register int bufsize; 65 register int caplen; 66 register u_char *bp; 67 struct sockaddr from; 68 int fromlen; 69 70 bp = (char *)p->buffer; 71 bufsize = p->bufsize; 72 if (p->md.pad > 0) { 73 bp += p->md.pad; 74 bufsize -= p->md.pad; 75 memset(p->buffer, 0, p->md.pad); 76 } 77 78 again: 79 do { 80 fromlen = sizeof(from); 81 cc = recvfrom(p->fd, bp, bufsize, 0, &from, &fromlen); 82 if (cc < 0) { 83 /* Don't choke when we get ptraced */ 84 switch (errno) { 85 86 case EINTR: 87 goto again; 88 89 case EWOULDBLOCK: 90 return (0); /* XXX */ 91 } 92 sprintf(p->errbuf, "read: %s", pcap_strerror(errno)); 93 return (-1); 94 } 95 } while (strcmp(p->md.device, from.sa_data)); 96 97 /* If we need have leading zero bytes, adjust count */ 98 cc += p->md.pad; 99 bp = p->buffer; 100 101 /* If we need to step over leading junk, adjust count and pointer */ 102 cc -= p->md.skip; 103 bp += p->md.skip; 104 105 /* Captured length can't exceed our read buffer size */ 106 caplen = cc; 107 if (caplen > bufsize) 108 caplen = bufsize; 109 110 /* Captured length can't exceed the snapshot length */ 111 if (caplen > p->snapshot) 112 caplen = p->snapshot; 113 114 if (p->fcode.bf_insns == NULL || 115 bpf_filter(p->fcode.bf_insns, bp, cc, caplen)) { 116 struct pcap_pkthdr h; 117 118 ++p->md.stat.ps_recv; 119 /* Get timestamp */ 120 if (ioctl(p->fd, SIOCGSTAMP, &h.ts) < 0) { 121 sprintf(p->errbuf, "SIOCGSTAMP: %s", 122 pcap_strerror(errno)); 123 return (-1); 124 } 125 h.len = cc; 126 h.caplen = caplen; 127 (*callback)(user, &h, bp); 128 return (1); 129 } 130 return (0); 131 } 132 133 pcap_t * 134 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 135 { 136 register int fd, broadcast; 137 register pcap_t *p; 138 struct ifreq ifr; 139 140 p = (pcap_t *)malloc(sizeof(*p)); 141 if (p == NULL) { 142 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 143 return (NULL); 144 } 145 memset((char *)p, 0, sizeof(*p)); 146 fd = -1; 147 148 /* XXX hack - map device name to link layer type */ 149 broadcast = 0; 150 if (strncmp("eth", device, 3) == 0) { 151 p->linktype = DLT_EN10MB; 152 ++broadcast; 153 } else if (strncmp("sl", device, 2) == 0) { 154 p->linktype = DLT_SLIP; 155 p->md.pad = 16; 156 } else if (strncmp("ppp", device, 3) == 0) { 157 p->linktype = DLT_PPP; 158 p->md.pad = 4; 159 } else if (strncmp("lo", device, 2) == 0) { 160 p->linktype = DLT_NULL; 161 p->md.pad = 2; 162 p->md.skip = 12; 163 } else { 164 sprintf(ebuf, "linux: unknown physical layer type"); 165 goto bad; 166 } 167 168 /* Linux is full of magic numbers */ 169 fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); 170 if (fd < 0) { 171 sprintf(ebuf, "linux socket: %s", pcap_strerror(errno)); 172 goto bad; 173 } 174 p->fd = fd; 175 176 177 p->bufsize = 4096; /* XXX */ 178 p->buffer = (u_char *)malloc(p->bufsize); 179 if (p->buffer == NULL) { 180 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 181 goto bad; 182 } 183 184 /* XXX */ 185 if (promisc && broadcast) { 186 memset(&ifr, 0, sizeof(ifr)); 187 strcpy(ifr.ifr_name, device); 188 if (ioctl(p->fd, SIOCGIFFLAGS, &ifr) < 0 ) { 189 sprintf(ebuf, "SIOCGIFFLAGS: %s", pcap_strerror(errno)); 190 goto bad; 191 } 192 saved_ifr = ifr; 193 ifr.ifr_flags |= IFF_PROMISC; 194 if (ioctl(p->fd, SIOCSIFFLAGS, &ifr) < 0 ) { 195 sprintf(ebuf, "SIOCSIFFLAGS: %s", pcap_strerror(errno)); 196 goto bad; 197 } 198 ifr.ifr_flags &= ~IFF_PROMISC; 199 atexit(linux_restore_ifr); 200 } 201 202 p->md.device = strdup(device); 203 if (p->md.device == NULL) { 204 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 205 goto bad; 206 } 207 p->snapshot = snaplen; 208 209 return (p); 210 bad: 211 if (fd >= 0) 212 (void)close(fd); 213 if (p->buffer != NULL) 214 free(p->buffer); 215 if (p->md.device != NULL) 216 free(p->md.device); 217 free(p); 218 return (NULL); 219 } 220 221 int 222 pcap_setfilter(pcap_t *p, struct bpf_program *fp) 223 { 224 225 p->fcode = *fp; 226 return (0); 227 } 228 229 void 230 linux_restore_ifr(void) 231 { 232 register int fd; 233 234 fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); 235 if (fd < 0) 236 fprintf(stderr, "linux socket: %s", pcap_strerror(errno)); 237 else if (ioctl(fd, SIOCSIFFLAGS, &saved_ifr) < 0) 238 fprintf(stderr, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno)); 239 } 240