pcap-snoop.c revision 127664
10SN/A/* 2157SN/A * Copyright (c) 1993, 1994, 1995, 1996, 1997 30SN/A * The Regents of the University of California. All rights reserved. 40SN/A * 50SN/A * Redistribution and use in source and binary forms, with or without 60SN/A * modification, are permitted provided that: (1) source code distributions 7157SN/A * retain the above copyright notice and this paragraph in its entirety, (2) 80SN/A * distributions including binary code include the above copyright notice and 9157SN/A * this paragraph in its entirety in the documentation or other materials 100SN/A * provided with the distribution, and (3) all advertising materials mentioning 110SN/A * features or use of this software display the following acknowledgement: 120SN/A * ``This product includes software developed by the University of California, 130SN/A * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140SN/A * the University nor the names of its contributors may be used to endorse 150SN/A * or promote products derived from this software without specific prior 160SN/A * written permission. 170SN/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180SN/A * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190SN/A * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200SN/A */ 21157SN/A#ifndef lint 22157SN/Astatic const char rcsid[] _U_ = 23157SN/A "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.45.2.5 2004/03/21 08:33:24 guy Exp $ (LBL)"; 240SN/A#endif 250SN/A 260SN/A#ifdef HAVE_CONFIG_H 270SN/A#include "config.h" 280SN/A#endif 290SN/A 300SN/A#include <sys/param.h> 310SN/A#include <sys/file.h> 320SN/A#include <sys/ioctl.h> 330SN/A#include <sys/socket.h> 340SN/A#include <sys/time.h> 350SN/A 360SN/A#include <net/raw.h> 370SN/A#include <net/if.h> 380SN/A 390SN/A#include <netinet/in.h> 400SN/A#include <netinet/in_systm.h> 410SN/A#include <netinet/ip.h> 420SN/A#include <netinet/if_ether.h> 430SN/A#include <netinet/ip_var.h> 440SN/A#include <netinet/udp.h> 450SN/A#include <netinet/udp_var.h> 460SN/A#include <netinet/tcp.h> 470SN/A#include <netinet/tcpip.h> 480SN/A 490SN/A#include <errno.h> 500SN/A#include <stdio.h> 510SN/A#include <stdlib.h> 520SN/A#include <string.h> 530SN/A#include <unistd.h> 540SN/A 550SN/A#include "pcap-int.h" 560SN/A 570SN/A#ifdef HAVE_OS_PROTO_H 580SN/A#include "os-proto.h" 590SN/A#endif 600SN/A 610SN/Astatic int 620SN/Apcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 630SN/A{ 640SN/A int cc; 650SN/A register struct snoopheader *sh; 660SN/A register int datalen; 670SN/A register int caplen; 680SN/A register u_char *cp; 690SN/A 700SN/Aagain: 710SN/A /* 720SN/A * Has "pcap_breakloop()" been called? 730SN/A */ 740SN/A if (p->break_loop) { 750SN/A /* 760SN/A * Yes - clear the flag that indicates that it 770SN/A * has, and return -2 to indicate that we were 780SN/A * told to break out of the loop. 790SN/A */ 800SN/A p->break_loop = 0; 810SN/A return (-2); 820SN/A } 830SN/A cc = read(p->fd, (char *)p->buffer, p->bufsize); 840SN/A if (cc < 0) { 850SN/A /* Don't choke when we get ptraced */ 860SN/A switch (errno) { 870SN/A 880SN/A case EINTR: 890SN/A goto again; 900SN/A 910SN/A case EWOULDBLOCK: 920SN/A return (0); /* XXX */ 930SN/A } 940SN/A snprintf(p->errbuf, sizeof(p->errbuf), 950SN/A "read: %s", pcap_strerror(errno)); 960SN/A return (-1); 970SN/A } 980SN/A sh = (struct snoopheader *)p->buffer; 990SN/A datalen = sh->snoop_packetlen; 1000SN/A caplen = (datalen < p->snapshot) ? datalen : p->snapshot; 1010SN/A cp = (u_char *)(sh + 1) + p->offset; /* XXX */ 1020SN/A 1030SN/A /* 1040SN/A * XXX unfortunately snoop loopback isn't exactly like 1050SN/A * BSD's. The address family is encoded in the first 2 1060SN/A * bytes rather than the first 4 bytes! Luckily the last 1070SN/A * two snoop loopback bytes are zeroed. 108 */ 109 if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) { 110 u_int *uip = (u_int *)cp; 111 *uip >>= 16; 112 } 113 114 if (p->fcode.bf_insns == NULL || 115 bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { 116 struct pcap_pkthdr h; 117 ++p->md.stat.ps_recv; 118 h.ts.tv_sec = sh->snoop_timestamp.tv_sec; 119 h.ts.tv_usec = sh->snoop_timestamp.tv_usec; 120 h.len = datalen; 121 h.caplen = caplen; 122 (*callback)(user, &h, cp); 123 return (1); 124 } 125 return (0); 126} 127 128static int 129pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps) 130{ 131 register struct rawstats *rs; 132 struct rawstats rawstats; 133 134 rs = &rawstats; 135 memset(rs, 0, sizeof(*rs)); 136 if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { 137 snprintf(p->errbuf, sizeof(p->errbuf), 138 "SIOCRAWSTATS: %s", pcap_strerror(errno)); 139 return (-1); 140 } 141 142 /* 143 * "ifdrops" are those dropped by the network interface 144 * due to resource shortages or hardware errors. 145 * 146 * "sbdrops" are those dropped due to socket buffer limits. 147 * 148 * As filter is done in userland, "sbdrops" counts packets 149 * regardless of whether they would've passed the filter. 150 * 151 * XXX - does this count *all* Snoop or Drain sockets, 152 * rather than just this socket? If not, why does it have 153 * both Snoop and Drain statistics? 154 */ 155 p->md.stat.ps_drop = 156 rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + 157 rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; 158 159 /* 160 * "ps_recv" counts only packets that passed the filter. 161 * As filtering is done in userland, this does not include 162 * packets dropped because we ran out of buffer space. 163 */ 164 *ps = p->md.stat; 165 return (0); 166} 167 168static void 169pcap_close_snoop(pcap_t *p) 170{ 171 if (p->buffer != NULL) 172 free(p->buffer); 173 if (p->fd >= 0) 174 close(p->fd); 175} 176 177/* XXX can't disable promiscuous */ 178pcap_t * 179pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, 180 char *ebuf) 181{ 182 int fd; 183 struct sockaddr_raw sr; 184 struct snoopfilter sf; 185 u_int v; 186 int ll_hdrlen; 187 int snooplen; 188 pcap_t *p; 189 struct ifreq ifr; 190 191 p = (pcap_t *)malloc(sizeof(*p)); 192 if (p == NULL) { 193 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", 194 pcap_strerror(errno)); 195 return (NULL); 196 } 197 memset(p, 0, sizeof(*p)); 198 fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); 199 if (fd < 0) { 200 snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop socket: %s", 201 pcap_strerror(errno)); 202 goto bad; 203 } 204 p->fd = fd; 205 memset(&sr, 0, sizeof(sr)); 206 sr.sr_family = AF_RAW; 207 (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname)); 208 if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { 209 snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop bind: %s", 210 pcap_strerror(errno)); 211 goto bad; 212 } 213 memset(&sf, 0, sizeof(sf)); 214 if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { 215 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s", 216 pcap_strerror(errno)); 217 goto bad; 218 } 219 v = 64 * 1024; 220 (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); 221 /* 222 * XXX hack - map device name to link layer type 223 */ 224 if (strncmp("et", device, 2) == 0 || /* Challenge 10 Mbit */ 225 strncmp("ec", device, 2) == 0 || /* Indigo/Indy 10 Mbit, 226 O2 10/100 */ 227 strncmp("ef", device, 2) == 0 || /* O200/2000 10/100 Mbit */ 228 strncmp("eg", device, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ 229 strncmp("gfe", device, 3) == 0 || /* GIO 100 Mbit */ 230 strncmp("fxp", device, 3) == 0 || /* Challenge VME Enet */ 231 strncmp("ep", device, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ 232 strncmp("vfe", device, 3) == 0 || /* Challenge VME 100Mbit */ 233 strncmp("fa", device, 2) == 0 || 234 strncmp("qaa", device, 3) == 0 || 235 strncmp("cip", device, 3) == 0 || 236 strncmp("el", device, 2) == 0) { 237 p->linktype = DLT_EN10MB; 238 p->offset = RAW_HDRPAD(sizeof(struct ether_header)); 239 ll_hdrlen = sizeof(struct ether_header); 240 } else if (strncmp("ipg", device, 3) == 0 || 241 strncmp("rns", device, 3) == 0 || /* O2/200/2000 FDDI */ 242 strncmp("xpi", device, 3) == 0) { 243 p->linktype = DLT_FDDI; 244 p->offset = 3; /* XXX yeah? */ 245 ll_hdrlen = 13; 246 } else if (strncmp("ppp", device, 3) == 0) { 247 p->linktype = DLT_RAW; 248 ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ 249 } else if (strncmp("qfa", device, 3) == 0) { 250 p->linktype = DLT_IP_OVER_FC; 251 ll_hdrlen = 24; 252 } else if (strncmp("pl", device, 2) == 0) { 253 p->linktype = DLT_RAW; 254 ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ 255 } else if (strncmp("lo", device, 2) == 0) { 256 p->linktype = DLT_NULL; 257 ll_hdrlen = 4; 258 } else { 259 snprintf(ebuf, PCAP_ERRBUF_SIZE, 260 "snoop: unknown physical layer type"); 261 goto bad; 262 } 263#ifdef SIOCGIFMTU 264 /* 265 * XXX - IRIX appears to give you an error if you try to set the 266 * capture length to be greater than the MTU, so let's try to get 267 * the MTU first and, if that succeeds, trim the snap length 268 * to be no greater than the MTU. 269 */ 270 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 271 if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { 272 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", 273 pcap_strerror(errno)); 274 goto bad; 275 } 276 /* 277 * OK, we got it. 278 * 279 * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an 280 * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" 281 * structure, others don't. 282 * 283 * I've no idea what's going on, so, if "ifr_mtu" isn't defined, 284 * we define it as "ifr_metric", as using that field appears to 285 * work on the versions that lack "ifr_mtu" (and, on those that 286 * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" 287 * members of the "ifr_ifru" union, which suggests that they 288 * may be interchangeable in this case). 289 */ 290#ifndef ifr_mtu 291#define ifr_mtu ifr_metric 292#endif 293 if (snaplen > ifr.ifr_mtu + ll_hdrlen) 294 snaplen = ifr.ifr_mtu + ll_hdrlen; 295#endif 296 297 /* 298 * The argument to SIOCSNOOPLEN is the number of link-layer 299 * payload bytes to capture - it doesn't count link-layer 300 * header bytes. 301 */ 302 snooplen = snaplen - ll_hdrlen; 303 if (snooplen < 0) 304 snooplen = 0; 305 if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { 306 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s", 307 pcap_strerror(errno)); 308 goto bad; 309 } 310 p->snapshot = snaplen; 311 v = 1; 312 if (ioctl(fd, SIOCSNOOPING, &v) < 0) { 313 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s", 314 pcap_strerror(errno)); 315 goto bad; 316 } 317 318 p->bufsize = 4096; /* XXX */ 319 p->buffer = (u_char *)malloc(p->bufsize); 320 if (p->buffer == NULL) { 321 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", 322 pcap_strerror(errno)); 323 goto bad; 324 } 325 326 /* 327 * "p->fd" is a socket, so "select()" should work on it. 328 */ 329 p->selectable_fd = p->fd; 330 331 p->read_op = pcap_read_snoop; 332 p->setfilter_op = install_bpf_program; /* no kernel filtering */ 333 p->set_datalink_op = NULL; /* can't change data link type */ 334 p->getnonblock_op = pcap_getnonblock_fd; 335 p->setnonblock_op = pcap_setnonblock_fd; 336 p->stats_op = pcap_stats_snoop; 337 p->close_op = pcap_close_snoop; 338 339 return (p); 340 bad: 341 (void)close(fd); 342 free(p); 343 return (NULL); 344} 345 346int 347pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 348{ 349 return (0); 350} 351