1 /* 2 * Copyright (c) 1996, 1997 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.15 97/10/02 22:39:37 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 #ifdef HAVE_NET_IF_ARP_H 33 #include <net/if_arp.h> 34 #else 35 #include <linux/if_arp.h> 36 #endif 37 #include <linux/if_ether.h> 38 39 #include <netinet/in.h> 40 41 #include <errno.h> 42 #include <malloc.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 static struct ifreq saved_ifr; 49 50 #include "pcap-int.h" 51 52 #include "gnuc.h" 53 #ifdef HAVE_OS_PROTO_H 54 #include "os-proto.h" 55 #endif 56 57 void linux_restore_ifr(void); 58 59 int 60 pcap_stats(pcap_t *p, struct pcap_stat *ps) 61 { 62 63 *ps = p->md.stat; 64 return (0); 65 } 66 67 int 68 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 69 { 70 register int cc; 71 register int bufsize; 72 register int caplen; 73 register u_char *bp; 74 struct sockaddr from; 75 int fromlen; 76 77 bp = p->buffer + p->offset; 78 bufsize = p->bufsize; 79 if (p->md.pad > 0) { 80 memset(bp, 0, p->md.pad); 81 bp += p->md.pad; 82 bufsize -= p->md.pad; 83 } 84 85 again: 86 do { 87 fromlen = sizeof(from); 88 cc = recvfrom(p->fd, bp, bufsize, 0, &from, &fromlen); 89 if (cc < 0) { 90 /* Don't choke when we get ptraced */ 91 switch (errno) { 92 93 case EINTR: 94 goto again; 95 96 case EWOULDBLOCK: 97 return (0); /* XXX */ 98 } 99 sprintf(p->errbuf, "read: %s", pcap_strerror(errno)); 100 return (-1); 101 } 102 } while (strcmp(p->md.device, from.sa_data)); 103 104 /* If we need have leading zero bytes, adjust count */ 105 cc += p->md.pad; 106 bp = p->buffer + p->offset; 107 108 /* If we need to step over leading junk, adjust count and pointer */ 109 cc -= p->md.skip; 110 bp += p->md.skip; 111 112 /* Captured length can't exceed our read buffer size */ 113 caplen = cc; 114 if (caplen > bufsize) 115 caplen = bufsize; 116 117 /* Captured length can't exceed the snapshot length */ 118 if (caplen > p->snapshot) 119 caplen = p->snapshot; 120 121 if (p->fcode.bf_insns == NULL || 122 bpf_filter(p->fcode.bf_insns, bp, cc, caplen)) { 123 struct pcap_pkthdr h; 124 125 ++p->md.stat.ps_recv; 126 /* Get timestamp */ 127 if (ioctl(p->fd, SIOCGSTAMP, &h.ts) < 0) { 128 sprintf(p->errbuf, "SIOCGSTAMP: %s", 129 pcap_strerror(errno)); 130 return (-1); 131 } 132 h.len = cc; 133 h.caplen = caplen; 134 (*callback)(user, &h, bp); 135 return (1); 136 } 137 return (0); 138 } 139 140 pcap_t * 141 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 142 { 143 register int fd, broadcast; 144 register pcap_t *p; 145 struct ifreq ifr; 146 struct sockaddr sa; 147 148 p = (pcap_t *)malloc(sizeof(*p)); 149 if (p == NULL) { 150 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 151 return (NULL); 152 } 153 memset(p, 0, sizeof(*p)); 154 fd = -1; 155 156 fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); 157 if (fd < 0) { 158 sprintf(ebuf, "socket: %s", pcap_strerror(errno)); 159 goto bad; 160 } 161 p->fd = fd; 162 163 /* Bind to the interface name */ 164 memset(&sa, 0, sizeof(sa)); 165 sa.sa_family = AF_INET; 166 (void)strncpy(sa.sa_data, device, sizeof(sa.sa_data)); 167 if (bind(p->fd, &sa, sizeof(sa))) { 168 sprintf(ebuf, "bind: %s: %s", device, pcap_strerror(errno)); 169 goto bad; 170 } 171 172 memset(&ifr, 0, sizeof(ifr)); 173 strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 174 if (ioctl(p->fd, SIOCGIFHWADDR, &ifr) < 0 ) { 175 sprintf(ebuf, "SIOCGIFHWADDR: %s", pcap_strerror(errno)); 176 goto bad; 177 } 178 broadcast = 0; 179 switch (ifr.ifr_hwaddr.sa_family) { 180 181 case ARPHRD_ETHER: 182 case ARPHRD_METRICOM: 183 p->linktype = DLT_EN10MB; 184 p->offset = 2; 185 ++broadcast; 186 break; 187 188 case ARPHRD_EETHER: 189 p->linktype = DLT_EN3MB; 190 ++broadcast; 191 break; 192 193 case ARPHRD_AX25: 194 p->linktype = DLT_AX25; 195 ++broadcast; 196 break; 197 198 case ARPHRD_PRONET: 199 p->linktype = DLT_PRONET; 200 break; 201 202 case ARPHRD_CHAOS: 203 p->linktype = DLT_CHAOS; 204 break; 205 206 case ARPHRD_IEEE802: 207 p->linktype = DLT_IEEE802; 208 ++broadcast; 209 break; 210 211 case ARPHRD_ARCNET: 212 p->linktype = DLT_ARCNET; 213 ++broadcast; 214 break; 215 216 case ARPHRD_SLIP: 217 case ARPHRD_CSLIP: 218 case ARPHRD_SLIP6: 219 case ARPHRD_CSLIP6: 220 case ARPHRD_PPP: 221 p->linktype = DLT_RAW; 222 break; 223 224 case ARPHRD_LOOPBACK: 225 p->linktype = DLT_NULL; 226 p->md.pad = 2; 227 p->md.skip = 12; 228 break; 229 230 #ifdef ARPHRD_FDDI 231 /* Not all versions of the kernel has this define */ 232 case ARPHRD_FDDI: 233 p->linktype = DLT_FDDI; 234 ++broadcast; 235 break; 236 #endif 237 238 #ifdef notdef 239 case ARPHRD_LOCALTLK: 240 case ARPHRD_NETROM: 241 case ARPHRD_APPLETLK: 242 case ARPHRD_DLCI: 243 case ARPHRD_RSRVD: 244 case ARPHRD_ADAPT: 245 case ARPHRD_TUNNEL: 246 case ARPHRD_TUNNEL6: 247 case ARPHRD_FRAD: 248 case ARPHRD_SKIP: 249 /* XXX currently do not know what to do with these... */ 250 abort(); 251 #endif 252 253 default: 254 sprintf(ebuf, "unknown physical layer type 0x%x", 255 ifr.ifr_hwaddr.sa_family); 256 goto bad; 257 } 258 259 /* Base the buffer size on the interface MTU */ 260 memset(&ifr, 0, sizeof(ifr)); 261 strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 262 if (ioctl(p->fd, SIOCGIFMTU, &ifr) < 0 ) { 263 sprintf(ebuf, "SIOCGIFMTU: %s", pcap_strerror(errno)); 264 goto bad; 265 } 266 267 /* Leave room for link header (which is never large under linux...) */ 268 p->bufsize = ifr.ifr_mtu + 64; 269 270 p->buffer = (u_char *)malloc(p->bufsize + p->offset); 271 if (p->buffer == NULL) { 272 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 273 goto bad; 274 } 275 276 /* XXX */ 277 if (promisc && broadcast) { 278 memset(&ifr, 0, sizeof(ifr)); 279 strcpy(ifr.ifr_name, device); 280 if (ioctl(p->fd, SIOCGIFFLAGS, &ifr) < 0 ) { 281 sprintf(ebuf, "SIOCGIFFLAGS: %s", pcap_strerror(errno)); 282 goto bad; 283 } 284 saved_ifr = ifr; 285 ifr.ifr_flags |= IFF_PROMISC; 286 if (ioctl(p->fd, SIOCSIFFLAGS, &ifr) < 0 ) { 287 sprintf(ebuf, "SIOCSIFFLAGS: %s", pcap_strerror(errno)); 288 goto bad; 289 } 290 ifr.ifr_flags &= ~IFF_PROMISC; 291 atexit(linux_restore_ifr); 292 } 293 294 p->md.device = strdup(device); 295 if (p->md.device == NULL) { 296 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 297 goto bad; 298 } 299 p->snapshot = snaplen; 300 301 return (p); 302 bad: 303 if (fd >= 0) 304 (void)close(fd); 305 if (p->buffer != NULL) 306 free(p->buffer); 307 if (p->md.device != NULL) 308 free(p->md.device); 309 free(p); 310 return (NULL); 311 } 312 313 int 314 pcap_setfilter(pcap_t *p, struct bpf_program *fp) 315 { 316 317 p->fcode = *fp; 318 return (0); 319 } 320 321 void 322 linux_restore_ifr(void) 323 { 324 register int fd; 325 326 fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); 327 if (fd < 0) 328 fprintf(stderr, "linux socket: %s", pcap_strerror(errno)); 329 else if (ioctl(fd, SIOCSIFFLAGS, &saved_ifr) < 0) 330 fprintf(stderr, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno)); 331 } 332