1 /* $OpenBSD: pcap.c,v 1.11 2007/09/02 15:19:18 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the Computer Systems 18 * Engineering Group at Lawrence Berkeley Laboratory. 19 * 4. Neither the name of the University nor of the Laboratory may be used 20 * to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/types.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 45 #ifdef HAVE_OS_PROTO_H 46 #include "os-proto.h" 47 #endif 48 49 #include "pcap-int.h" 50 51 static const char pcap_version_string[] = "OpenBSD libpcap"; 52 53 int 54 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 55 { 56 57 if (p->sf.rfile != NULL) 58 return (pcap_offline_read(p, cnt, callback, user)); 59 return (pcap_read(p, cnt, callback, user)); 60 } 61 62 int 63 pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 64 { 65 register int n; 66 67 for (;;) { 68 if (p->sf.rfile != NULL) 69 n = pcap_offline_read(p, cnt, callback, user); 70 else { 71 /* 72 * XXX keep reading until we get something 73 * (or an error occurs) 74 */ 75 do { 76 n = pcap_read(p, cnt, callback, user); 77 } while (n == 0); 78 } 79 if (n <= 0) 80 return (n); 81 if (cnt > 0) { 82 cnt -= n; 83 if (cnt <= 0) 84 return (0); 85 } 86 } 87 } 88 89 struct singleton { 90 struct pcap_pkthdr *hdr; 91 const u_char *pkt; 92 }; 93 94 95 static void 96 pcap_oneshot(u_char *userData, const struct pcap_pkthdr *h, const u_char *pkt) 97 { 98 struct singleton *sp = (struct singleton *)userData; 99 *sp->hdr = *h; 100 sp->pkt = pkt; 101 } 102 103 const u_char * 104 pcap_next(pcap_t *p, struct pcap_pkthdr *h) 105 { 106 struct singleton s; 107 108 s.hdr = h; 109 if (pcap_dispatch(p, 1, pcap_oneshot, (u_char*)&s) <= 0) 110 return (0); 111 return (s.pkt); 112 } 113 114 struct pkt_for_fakecallback { 115 struct pcap_pkthdr *hdr; 116 const u_char **pkt; 117 }; 118 119 static void 120 pcap_fakecallback(u_char *userData, const struct pcap_pkthdr *h, 121 const u_char *pkt) 122 { 123 struct pkt_for_fakecallback *sp = (struct pkt_for_fakecallback *)userData; 124 125 *sp->hdr = *h; 126 *sp->pkt = pkt; 127 } 128 129 int 130 pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, 131 const u_char **pkt_data) 132 { 133 struct pkt_for_fakecallback s; 134 135 s.hdr = &p->pcap_header; 136 s.pkt = pkt_data; 137 138 /* Saves a pointer to the packet headers */ 139 *pkt_header= &p->pcap_header; 140 141 if (p->sf.rfile != NULL) { 142 int status; 143 144 /* We are on an offline capture */ 145 status = pcap_offline_read(p, 1, pcap_fakecallback, 146 (u_char *)&s); 147 148 /* 149 * Return codes for pcap_offline_read() are: 150 * - 0: EOF 151 * - -1: error 152 * - >1: OK 153 * The first one ('0') conflicts with the return code of 154 * 0 from pcap_read() meaning "no packets arrived before 155 * the timeout expired", so we map it to -2 so you can 156 * distinguish between an EOF from a savefile and a 157 * "no packets arrived before the timeout expired, try 158 * again" from a live capture. 159 */ 160 if (status == 0) 161 return (-2); 162 else 163 return (status); 164 } 165 166 /* 167 * Return codes for pcap_read() are: 168 * - 0: timeout 169 * - -1: error 170 * - -2: loop was broken out of with pcap_breakloop() 171 * - >1: OK 172 * The first one ('0') conflicts with the return code of 0 from 173 * pcap_offline_read() meaning "end of file". 174 */ 175 return (pcap_read(p, 1, pcap_fakecallback, (u_char *)&s)); 176 } 177 178 /* 179 * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. 180 */ 181 void 182 pcap_breakloop(pcap_t *p) 183 { 184 p->break_loop = 1; 185 } 186 187 int 188 pcap_datalink(pcap_t *p) 189 { 190 return (p->linktype); 191 } 192 193 int 194 pcap_list_datalinks(pcap_t *p, int **dlt_buffer) 195 { 196 if (p->dlt_count == 0) { 197 /* 198 * We couldn't fetch the list of DLTs, which means 199 * this platform doesn't support changing the 200 * DLT for an interface. Return a list of DLTs 201 * containing only the DLT this device supports. 202 */ 203 *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); 204 if (*dlt_buffer == NULL) { 205 (void)snprintf(p->errbuf, sizeof(p->errbuf), 206 "malloc: %s", pcap_strerror(errno)); 207 return (-1); 208 } 209 **dlt_buffer = p->linktype; 210 return (1); 211 } else { 212 *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count); 213 if (*dlt_buffer == NULL) { 214 (void)snprintf(p->errbuf, sizeof(p->errbuf), 215 "malloc: %s", pcap_strerror(errno)); 216 return (-1); 217 } 218 (void)memcpy(*dlt_buffer, p->dlt_list, 219 sizeof(**dlt_buffer) * p->dlt_count); 220 return (p->dlt_count); 221 } 222 } 223 224 struct dlt_choice { 225 const char *name; 226 const char *description; 227 int dlt; 228 }; 229 230 static struct dlt_choice dlts[] = { 231 #define DLT_CHOICE(code, description) { #code, description, code } 232 DLT_CHOICE(DLT_NULL, "no link-layer encapsulation"), 233 DLT_CHOICE(DLT_EN10MB, "Ethernet (10Mb)"), 234 DLT_CHOICE(DLT_EN3MB, "Experimental Ethernet (3Mb)"), 235 DLT_CHOICE(DLT_AX25, "Amateur Radio AX.25"), 236 DLT_CHOICE(DLT_PRONET, "Proteon ProNET Token Ring"), 237 DLT_CHOICE(DLT_CHAOS, "Chaos"), 238 DLT_CHOICE(DLT_IEEE802, "IEEE 802 Networks"), 239 DLT_CHOICE(DLT_ARCNET, "ARCNET"), 240 DLT_CHOICE(DLT_SLIP, "Serial Line IP"), 241 DLT_CHOICE(DLT_PPP, "Point-to-point Protocol"), 242 DLT_CHOICE(DLT_FDDI, "FDDI"), 243 DLT_CHOICE(DLT_ATM_RFC1483, "LLC/SNAP encapsulated atm"), 244 DLT_CHOICE(DLT_LOOP, "loopback type (af header)"), 245 DLT_CHOICE(DLT_ENC, "IPSEC enc type (af header, spi, flags)"), 246 DLT_CHOICE(DLT_RAW, "raw IP"), 247 DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS Serial Line IP"), 248 DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS Point-to-point Protocol"), 249 DLT_CHOICE(DLT_OLD_PFLOG, "Packet filter logging, old (XXX remove?)"), 250 DLT_CHOICE(DLT_PFSYNC, "Packet filter state syncing"), 251 DLT_CHOICE(DLT_PPP_ETHER, "PPP over Ethernet; session only w/o ether header"), 252 DLT_CHOICE(DLT_IEEE802_11, "IEEE 802.11 wireless"), 253 DLT_CHOICE(DLT_PFLOG, "Packet filter logging, by pcap people"), 254 DLT_CHOICE(DLT_IEEE802_11_RADIO, "IEEE 802.11 plus WLAN header"), 255 #undef DLT_CHOICE 256 { NULL, NULL, -1} 257 }; 258 259 int 260 pcap_datalink_name_to_val(const char *name) 261 { 262 int i; 263 264 for (i = 0; dlts[i].name != NULL; i++) { 265 /* Skip leading "DLT_" */ 266 if (strcasecmp(dlts[i].name + 4, name) == 0) 267 return (dlts[i].dlt); 268 } 269 return (-1); 270 } 271 272 const char * 273 pcap_datalink_val_to_name(int dlt) 274 { 275 int i; 276 277 for (i = 0; dlts[i].name != NULL; i++) { 278 if (dlts[i].dlt == dlt) 279 return (dlts[i].name + 4); /* Skip leading "DLT_" */ 280 } 281 return (NULL); 282 } 283 284 const char * 285 pcap_datalink_val_to_description(int dlt) 286 { 287 int i; 288 289 for (i = 0; dlts[i].name != NULL; i++) { 290 if (dlts[i].dlt == dlt) 291 return (dlts[i].description); 292 } 293 return (NULL); 294 } 295 296 int 297 pcap_snapshot(pcap_t *p) 298 { 299 return (p->snapshot); 300 } 301 302 int 303 pcap_is_swapped(pcap_t *p) 304 { 305 return (p->sf.swapped); 306 } 307 308 int 309 pcap_major_version(pcap_t *p) 310 { 311 return (p->sf.version_major); 312 } 313 314 int 315 pcap_minor_version(pcap_t *p) 316 { 317 return (p->sf.version_minor); 318 } 319 320 FILE * 321 pcap_file(pcap_t *p) 322 { 323 return (p->sf.rfile); 324 } 325 326 int 327 pcap_fileno(pcap_t *p) 328 { 329 return (p->fd); 330 } 331 332 void 333 pcap_perror(pcap_t *p, char *prefix) 334 { 335 fprintf(stderr, "%s: %s\n", prefix, p->errbuf); 336 } 337 338 int 339 pcap_get_selectable_fd(pcap_t *p) 340 { 341 return (p->fd); 342 } 343 344 char * 345 pcap_geterr(pcap_t *p) 346 { 347 return (p->errbuf); 348 } 349 350 int 351 pcap_getnonblock(pcap_t *p, char *errbuf) 352 { 353 int fdflags; 354 355 fdflags = fcntl(p->fd, F_GETFL, 0); 356 if (fdflags == -1) { 357 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", 358 pcap_strerror(errno)); 359 return (-1); 360 } 361 if (fdflags & O_NONBLOCK) 362 return (1); 363 else 364 return (0); 365 } 366 367 int 368 pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) 369 { 370 int fdflags; 371 372 fdflags = fcntl(p->fd, F_GETFL, 0); 373 if (fdflags == -1) { 374 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", 375 pcap_strerror(errno)); 376 return (-1); 377 } 378 if (nonblock) 379 fdflags |= O_NONBLOCK; 380 else 381 fdflags &= ~O_NONBLOCK; 382 if (fcntl(p->fd, F_SETFL, fdflags) == -1) { 383 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", 384 pcap_strerror(errno)); 385 return (-1); 386 } 387 return (0); 388 } 389 390 /* 391 * Not all systems have strerror(). 392 */ 393 char * 394 pcap_strerror(int errnum) 395 { 396 #ifdef HAVE_STRERROR 397 return (strerror(errnum)); 398 #else 399 extern int sys_nerr; 400 extern const char *const sys_errlist[]; 401 static char ebuf[20]; 402 403 if ((unsigned int)errnum < sys_nerr) 404 return ((char *)sys_errlist[errnum]); 405 (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); 406 return(ebuf); 407 #endif 408 } 409 410 pcap_t * 411 pcap_open_dead(int linktype, int snaplen) 412 { 413 pcap_t *p; 414 415 p = malloc(sizeof(*p)); 416 if (p == NULL) 417 return NULL; 418 memset (p, 0, sizeof(*p)); 419 p->snapshot = snaplen; 420 p->linktype = linktype; 421 p->fd = -1; 422 return p; 423 } 424 425 void 426 pcap_close(pcap_t *p) 427 { 428 /*XXX*/ 429 if (p->fd >= 0) 430 close(p->fd); 431 if (p->sf.rfile != NULL) { 432 (void)fclose(p->sf.rfile); 433 if (p->sf.base != NULL) 434 free(p->sf.base); 435 } else if (p->buffer != NULL) 436 free(p->buffer); 437 #ifdef linux 438 if (p->md.device != NULL) 439 free(p->md.device); 440 #endif 441 pcap_freecode(&p->fcode); 442 if (p->dlt_list != NULL) 443 free(p->dlt_list); 444 free(p); 445 } 446 447 const char * 448 pcap_lib_version(void) 449 { 450 return (pcap_version_string); 451 } 452 453