1 /* 2 * Copyright (c) 1993, 1994, 1995, 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 char rcsid[] = 23 "@(#)$Header: pcap-snoop.c,v 1.15 96/07/15 00:48:52 leres Exp $ (LBL)"; 24 #endif 25 26 #include <sys/param.h> 27 #include <sys/file.h> 28 #include <sys/ioctl.h> 29 #include <sys/socket.h> 30 #include <sys/time.h> 31 32 #include <net/raw.h> 33 #include <net/if.h> 34 35 #include <netinet/in.h> 36 #include <netinet/in_systm.h> 37 #include <netinet/ip.h> 38 #include <netinet/if_ether.h> 39 #include <netinet/ip_var.h> 40 #include <netinet/udp.h> 41 #include <netinet/udp_var.h> 42 #include <netinet/tcp.h> 43 #include <netinet/tcpip.h> 44 45 #include <errno.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "pcap-int.h" 52 53 #include "gnuc.h" 54 #ifdef HAVE_OS_PROTO_H 55 #include "os-proto.h" 56 #endif 57 58 int 59 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 60 { 61 int cc; 62 register struct snoopheader *sh; 63 register int datalen; 64 register int caplen; 65 register u_char *cp; 66 67 again: 68 cc = read(p->fd, (char *)p->buffer, p->bufsize); 69 if (cc < 0) { 70 /* Don't choke when we get ptraced */ 71 switch (errno) { 72 73 case EINTR: 74 goto again; 75 76 case EWOULDBLOCK: 77 return (0); /* XXX */ 78 } 79 sprintf(p->errbuf, "read: %s", pcap_strerror(errno)); 80 return (-1); 81 } 82 sh = (struct snoopheader *)p->buffer; 83 datalen = sh->snoop_packetlen; 84 caplen = (datalen < p->snapshot) ? datalen : p->snapshot; 85 cp = (u_char *)(sh + 1) + p->offset; /* XXX */ 86 87 if (p->fcode.bf_insns == NULL || 88 bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { 89 struct pcap_pkthdr h; 90 ++p->md.stat.ps_recv; 91 h.ts = sh->snoop_timestamp; 92 h.len = datalen; 93 h.caplen = caplen; 94 (*callback)(user, &h, cp); 95 return (1); 96 } 97 return (0); 98 } 99 100 int 101 pcap_stats(pcap_t *p, struct pcap_stat *ps) 102 { 103 register struct rawstats *rs; 104 struct rawstats rawstats; 105 106 rs = &rawstats; 107 bzero((char *)rs, sizeof(*rs)); 108 if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { 109 sprintf(p->errbuf, "SIOCRAWSTATS: %s", pcap_strerror(errno)); 110 return (-1); 111 } 112 113 p->md.stat.ps_drop = 114 rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + 115 rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; 116 117 *ps = p->md.stat; 118 return (0); 119 } 120 121 /* XXX can't disable promiscuous */ 122 pcap_t * 123 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 124 { 125 int fd; 126 struct sockaddr_raw sr; 127 struct snoopfilter sf; 128 u_int v; 129 pcap_t *p; 130 131 p = (pcap_t *)malloc(sizeof(*p)); 132 if (p == NULL) { 133 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 134 return (NULL); 135 } 136 bzero((char *)p, sizeof(*p)); 137 fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); 138 if (fd < 0) { 139 sprintf(ebuf, "snoop socket: %s", pcap_strerror(errno)); 140 goto bad; 141 } 142 p->fd = fd; 143 bzero((char *)&sr, sizeof(sr)); 144 sr.sr_family = AF_RAW; 145 (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname)); 146 if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { 147 sprintf(ebuf, "snoop bind: %s", pcap_strerror(errno)); 148 goto bad; 149 } 150 bzero((char *)&sf, sizeof(sf)); 151 if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { 152 sprintf(ebuf, "SIOCADDSNOOP: %s", pcap_strerror(errno)); 153 goto bad; 154 } 155 v = 64 * 1024; 156 (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); 157 if (ioctl(fd, SIOCSNOOPLEN, &snaplen) < 0) { 158 sprintf(ebuf, "SIOCSNOOPLEN: %s", pcap_strerror(errno)); 159 goto bad; 160 } 161 p->snapshot = snaplen; 162 v = 1; 163 if (ioctl(fd, SIOCSNOOPING, &v) < 0) { 164 sprintf(ebuf, "SIOCSNOOPING: %s", pcap_strerror(errno)); 165 goto bad; 166 } 167 /* 168 * XXX hack - map device name to link layer type 169 */ 170 if (strncmp("et", device, 2) == 0 || 171 strncmp("ec", device, 2) == 0) { 172 p->linktype = DLT_EN10MB; 173 p->offset = RAW_HDRPAD(sizeof(struct ether_header)); 174 } else if (strncmp("ipg", device, 3) == 0 || 175 strncmp("xpi", device, 3) == 0) { 176 p->linktype = DLT_FDDI; 177 p->offset = 3; /* XXX yeah? */ 178 } else if (strncmp("lo", device, 2) == 0) { 179 p->linktype = DLT_NULL; 180 } else { 181 sprintf(ebuf, "snoop: unknown physical layer type"); 182 goto bad; 183 } 184 185 p->bufsize = 4096; /* XXX */ 186 p->buffer = (u_char *)malloc(p->bufsize); 187 if (p->buffer == NULL) { 188 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 189 goto bad; 190 } 191 192 return (p); 193 bad: 194 (void)close(fd); 195 free(p); 196 return (NULL); 197 } 198 199 int 200 pcap_setfilter(pcap_t *p, struct bpf_program *fp) 201 { 202 203 p->fcode = *fp; 204 return (0); 205 } 206