1 /* $NetBSD: pcap-snoop.c,v 1.3 2015/03/31 21:39:42 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994, 1995, 1996, 1997 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: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #include <sys/cdefs.h> 25 __RCSID("$NetBSD: pcap-snoop.c,v 1.3 2015/03/31 21:39:42 christos Exp $"); 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #include <sys/param.h> 32 #include <sys/file.h> 33 #include <sys/ioctl.h> 34 #include <sys/socket.h> 35 #include <sys/time.h> 36 37 #include <net/raw.h> 38 #include <net/if.h> 39 40 #include <netinet/in.h> 41 #include <netinet/in_systm.h> 42 #include <netinet/ip.h> 43 #include <netinet/if_ether.h> 44 #include <netinet/ip_var.h> 45 #include <netinet/udp.h> 46 #include <netinet/udp_var.h> 47 #include <netinet/tcp.h> 48 #include <netinet/tcpip.h> 49 50 #include <errno.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include "pcap-int.h" 57 58 #ifdef HAVE_OS_PROTO_H 59 #include "os-proto.h" 60 #endif 61 62 /* 63 * Private data for capturing on snoop devices. 64 */ 65 struct pcap_snoop { 66 struct pcap_stat stat; 67 }; 68 69 static int 70 pcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 71 { 72 struct pcap_snoop *psn = p->priv; 73 int cc; 74 register struct snoopheader *sh; 75 register u_int datalen; 76 register u_int caplen; 77 register u_char *cp; 78 79 again: 80 /* 81 * Has "pcap_breakloop()" been called? 82 */ 83 if (p->break_loop) { 84 /* 85 * Yes - clear the flag that indicates that it 86 * has, and return -2 to indicate that we were 87 * told to break out of the loop. 88 */ 89 p->break_loop = 0; 90 return (-2); 91 } 92 cc = read(p->fd, (char *)p->buffer, p->bufsize); 93 if (cc < 0) { 94 /* Don't choke when we get ptraced */ 95 switch (errno) { 96 97 case EINTR: 98 goto again; 99 100 case EWOULDBLOCK: 101 return (0); /* XXX */ 102 } 103 snprintf(p->errbuf, sizeof(p->errbuf), 104 "read: %s", pcap_strerror(errno)); 105 return (-1); 106 } 107 sh = (struct snoopheader *)p->buffer; 108 datalen = sh->snoop_packetlen; 109 110 /* 111 * XXX - Sigh, snoop_packetlen is a 16 bit quantity. If we 112 * got a short length, but read a full sized snoop pakcet, 113 * assume we overflowed and add back the 64K... 114 */ 115 if (cc == (p->snapshot + sizeof(struct snoopheader)) && 116 (datalen < p->snapshot)) 117 datalen += (64 * 1024); 118 119 caplen = (datalen < p->snapshot) ? datalen : p->snapshot; 120 cp = (u_char *)(sh + 1) + p->offset; /* XXX */ 121 122 /* 123 * XXX unfortunately snoop loopback isn't exactly like 124 * BSD's. The address family is encoded in the first 2 125 * bytes rather than the first 4 bytes! Luckily the last 126 * two snoop loopback bytes are zeroed. 127 */ 128 if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) { 129 u_int *uip = (u_int *)cp; 130 *uip >>= 16; 131 } 132 133 if (p->fcode.bf_insns == NULL || 134 bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { 135 struct pcap_pkthdr h; 136 ++psn->stat.ps_recv; 137 h.ts.tv_sec = sh->snoop_timestamp.tv_sec; 138 h.ts.tv_usec = sh->snoop_timestamp.tv_usec; 139 h.len = datalen; 140 h.caplen = caplen; 141 (*callback)(user, &h, cp); 142 return (1); 143 } 144 return (0); 145 } 146 147 static int 148 pcap_inject_snoop(pcap_t *p, const void *buf, size_t size) 149 { 150 int ret; 151 152 /* 153 * XXX - libnet overwrites the source address with what I 154 * presume is the interface's address; is that required? 155 */ 156 ret = write(p->fd, buf, size); 157 if (ret == -1) { 158 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 159 pcap_strerror(errno)); 160 return (-1); 161 } 162 return (ret); 163 } 164 165 static int 166 pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps) 167 { 168 struct pcap_snoop *psn = p->priv; 169 register struct rawstats *rs; 170 struct rawstats rawstats; 171 172 rs = &rawstats; 173 memset(rs, 0, sizeof(*rs)); 174 if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { 175 snprintf(p->errbuf, sizeof(p->errbuf), 176 "SIOCRAWSTATS: %s", pcap_strerror(errno)); 177 return (-1); 178 } 179 180 /* 181 * "ifdrops" are those dropped by the network interface 182 * due to resource shortages or hardware errors. 183 * 184 * "sbdrops" are those dropped due to socket buffer limits. 185 * 186 * As filter is done in userland, "sbdrops" counts packets 187 * regardless of whether they would've passed the filter. 188 * 189 * XXX - does this count *all* Snoop or Drain sockets, 190 * rather than just this socket? If not, why does it have 191 * both Snoop and Drain statistics? 192 */ 193 psn->stat.ps_drop = 194 rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + 195 rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; 196 197 /* 198 * "ps_recv" counts only packets that passed the filter. 199 * As filtering is done in userland, this does not include 200 * packets dropped because we ran out of buffer space. 201 */ 202 *ps = psn->stat; 203 return (0); 204 } 205 206 /* XXX can't disable promiscuous */ 207 static int 208 pcap_activate_snoop(pcap_t *p) 209 { 210 int fd; 211 struct sockaddr_raw sr; 212 struct snoopfilter sf; 213 u_int v; 214 int ll_hdrlen; 215 int snooplen; 216 struct ifreq ifr; 217 218 fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); 219 if (fd < 0) { 220 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop socket: %s", 221 pcap_strerror(errno)); 222 goto bad; 223 } 224 p->fd = fd; 225 memset(&sr, 0, sizeof(sr)); 226 sr.sr_family = AF_RAW; 227 (void)strncpy(sr.sr_ifname, p->opt.source, sizeof(sr.sr_ifname)); 228 if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { 229 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop bind: %s", 230 pcap_strerror(errno)); 231 goto bad; 232 } 233 memset(&sf, 0, sizeof(sf)); 234 if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { 235 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s", 236 pcap_strerror(errno)); 237 goto bad; 238 } 239 if (p->opt.buffer_size != 0) 240 v = p->opt.buffer_size; 241 else 242 v = 64 * 1024; /* default to 64K buffer size */ 243 (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); 244 /* 245 * XXX hack - map device name to link layer type 246 */ 247 if (strncmp("et", p->opt.source, 2) == 0 || /* Challenge 10 Mbit */ 248 strncmp("ec", p->opt.source, 2) == 0 || /* Indigo/Indy 10 Mbit, 249 O2 10/100 */ 250 strncmp("ef", p->opt.source, 2) == 0 || /* O200/2000 10/100 Mbit */ 251 strncmp("eg", p->opt.source, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ 252 strncmp("gfe", p->opt.source, 3) == 0 || /* GIO 100 Mbit */ 253 strncmp("fxp", p->opt.source, 3) == 0 || /* Challenge VME Enet */ 254 strncmp("ep", p->opt.source, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ 255 strncmp("vfe", p->opt.source, 3) == 0 || /* Challenge VME 100Mbit */ 256 strncmp("fa", p->opt.source, 2) == 0 || 257 strncmp("qaa", p->opt.source, 3) == 0 || 258 strncmp("cip", p->opt.source, 3) == 0 || 259 strncmp("el", p->opt.source, 2) == 0) { 260 p->linktype = DLT_EN10MB; 261 p->offset = RAW_HDRPAD(sizeof(struct ether_header)); 262 ll_hdrlen = sizeof(struct ether_header); 263 /* 264 * This is (presumably) a real Ethernet capture; give it a 265 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 266 * that an application can let you choose it, in case you're 267 * capturing DOCSIS traffic that a Cisco Cable Modem 268 * Termination System is putting out onto an Ethernet (it 269 * doesn't put an Ethernet header onto the wire, it puts raw 270 * DOCSIS frames out on the wire inside the low-level 271 * Ethernet framing). 272 * 273 * XXX - are there any sorts of "fake Ethernet" that have 274 * Ethernet link-layer headers but that *shouldn't offer 275 * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it 276 * or get traffic bridged onto it? "el" is for ATM LANE 277 * Ethernet devices, so that might be the case for them; 278 * the same applies for "qaa" classical IP devices. If 279 * "fa" devices are for FORE SPANS, that'd apply to them 280 * as well; what are "cip" devices - some other ATM 281 * Classical IP devices? 282 */ 283 p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 284 /* 285 * If that fails, just leave the list empty. 286 */ 287 if (p->dlt_list != NULL) { 288 p->dlt_list[0] = DLT_EN10MB; 289 p->dlt_list[1] = DLT_DOCSIS; 290 p->dlt_count = 2; 291 } 292 } else if (strncmp("ipg", p->opt.source, 3) == 0 || 293 strncmp("rns", p->opt.source, 3) == 0 || /* O2/200/2000 FDDI */ 294 strncmp("xpi", p->opt.source, 3) == 0) { 295 p->linktype = DLT_FDDI; 296 p->offset = 3; /* XXX yeah? */ 297 ll_hdrlen = 13; 298 } else if (strncmp("ppp", p->opt.source, 3) == 0) { 299 p->linktype = DLT_RAW; 300 ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ 301 } else if (strncmp("qfa", p->opt.source, 3) == 0) { 302 p->linktype = DLT_IP_OVER_FC; 303 ll_hdrlen = 24; 304 } else if (strncmp("pl", p->opt.source, 2) == 0) { 305 p->linktype = DLT_RAW; 306 ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ 307 } else if (strncmp("lo", p->opt.source, 2) == 0) { 308 p->linktype = DLT_NULL; 309 ll_hdrlen = 4; 310 } else { 311 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 312 "snoop: unknown physical layer type"); 313 goto bad; 314 } 315 316 if (p->opt.rfmon) { 317 /* 318 * No monitor mode on Irix (no Wi-Fi devices on 319 * hardware supported by Irix). 320 */ 321 return (PCAP_ERROR_RFMON_NOTSUP); 322 } 323 324 #ifdef SIOCGIFMTU 325 /* 326 * XXX - IRIX appears to give you an error if you try to set the 327 * capture length to be greater than the MTU, so let's try to get 328 * the MTU first and, if that succeeds, trim the snap length 329 * to be no greater than the MTU. 330 */ 331 (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); 332 if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { 333 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", 334 pcap_strerror(errno)); 335 goto bad; 336 } 337 /* 338 * OK, we got it. 339 * 340 * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an 341 * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" 342 * structure, others don't. 343 * 344 * I've no idea what's going on, so, if "ifr_mtu" isn't defined, 345 * we define it as "ifr_metric", as using that field appears to 346 * work on the versions that lack "ifr_mtu" (and, on those that 347 * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" 348 * members of the "ifr_ifru" union, which suggests that they 349 * may be interchangeable in this case). 350 */ 351 #ifndef ifr_mtu 352 #define ifr_mtu ifr_metric 353 #endif 354 if (p->snapshot > ifr.ifr_mtu + ll_hdrlen) 355 p->snapshot = ifr.ifr_mtu + ll_hdrlen; 356 #endif 357 358 /* 359 * The argument to SIOCSNOOPLEN is the number of link-layer 360 * payload bytes to capture - it doesn't count link-layer 361 * header bytes. 362 */ 363 snooplen = p->snapshot - ll_hdrlen; 364 if (snooplen < 0) 365 snooplen = 0; 366 if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { 367 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s", 368 pcap_strerror(errno)); 369 goto bad; 370 } 371 v = 1; 372 if (ioctl(fd, SIOCSNOOPING, &v) < 0) { 373 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s", 374 pcap_strerror(errno)); 375 goto bad; 376 } 377 378 p->bufsize = 4096; /* XXX */ 379 p->buffer = (u_char *)malloc(p->bufsize); 380 if (p->buffer == NULL) { 381 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", 382 pcap_strerror(errno)); 383 goto bad; 384 } 385 386 /* 387 * "p->fd" is a socket, so "select()" should work on it. 388 */ 389 p->selectable_fd = p->fd; 390 391 p->read_op = pcap_read_snoop; 392 p->inject_op = pcap_inject_snoop; 393 p->setfilter_op = install_bpf_program; /* no kernel filtering */ 394 p->setdirection_op = NULL; /* Not implemented. */ 395 p->set_datalink_op = NULL; /* can't change data link type */ 396 p->getnonblock_op = pcap_getnonblock_fd; 397 p->setnonblock_op = pcap_setnonblock_fd; 398 p->stats_op = pcap_stats_snoop; 399 400 return (0); 401 bad: 402 pcap_cleanup_live_common(p); 403 return (PCAP_ERROR); 404 } 405 406 pcap_t * 407 pcap_create_interface(const char *device, char *ebuf) 408 { 409 pcap_t *p; 410 411 p = pcap_create_common(device, ebuf, sizeof (struct pcap_snoop)); 412 if (p == NULL) 413 return (NULL); 414 415 p->activate_op = pcap_activate_snoop; 416 return (p); 417 } 418 419 int 420 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 421 { 422 return (0); 423 } 424