pcap_t * pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) { register char *cp; char *eos; register pcap_t *p; register int ppa; register dl_info_ack_t *infop; #ifdef HAVE_SYS_BUFMOD_H bpf_u_int32 ss, flag; #ifdef HAVE_SOLARIS register char *release; bpf_u_int32 osmajor, osminor, osmicro; #endif #endif bpf_u_int32 buf[MAXDLBUF]; char dname[100]; #ifndef HAVE_DEV_DLPI char dname2[100]; #endif p = (pcap_t *)malloc(sizeof(*p)); if (p == NULL) { strcpy(ebuf, pcap_strerror(errno)); return (NULL); } memset(p, 0, sizeof(*p)); /* ** Determine device and ppa */ cp = strpbrk(device, "0123456789"); if (cp == NULL) { sprintf(ebuf, "%s missing unit number", device); goto bad; } ppa = strtol(cp, &eos, 10); if (*eos != '\0') { sprintf(ebuf, "%s bad unit number", device); goto bad; } if (*device == '/') strcpy(dname, device); else sprintf(dname, "%s/%s", PCAP_DEV_PREFIX, device); #ifdef HAVE_DEV_DLPI /* Map network device to /dev/dlpi unit */ cp = "/dev/dlpi"; if ((p->fd = open(cp, O_RDWR)) < 0) { sprintf(ebuf, "%s: %s", cp, pcap_strerror(errno)); goto bad; } /* Map network interface to /dev/dlpi unit */ ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); if (ppa < 0) goto bad; #else /* Try device without unit number */ strcpy(dname2, dname); cp = strchr(dname, *cp); *cp = '\0'; if ((p->fd = open(dname, O_RDWR)) < 0) { if (errno != ENOENT) { sprintf(ebuf, "%s: %s", dname, pcap_strerror(errno)); goto bad; } /* Try again with unit number */ if ((p->fd = open(dname2, O_RDWR)) < 0) { sprintf(ebuf, "%s: %s", dname2, pcap_strerror(errno)); goto bad; } /* XXX Assume unit zero */ ppa = 0; } #endif p->snapshot = snaplen; /* ** Attach if "style 2" provider */ if (dlinforeq(p->fd, ebuf) < 0 || dlinfoack(p->fd, (char *)buf, ebuf) < 0) goto bad; infop = &((union DL_primitives *)buf)->info_ack; if (infop->dl_provider_style == DL_STYLE2 && (dlattachreq(p->fd, ppa, ebuf) < 0 || dlokack(p->fd, "attach", (char *)buf, ebuf) < 0)) goto bad; /* ** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if ** using SINIX) */ #if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix) if (dlbindreq(p->fd, 0, ebuf) < 0 || dlbindack(p->fd, (char *)buf, ebuf) < 0) goto bad; #endif if (promisc) { /* ** Enable promiscuous */ if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 || dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0) goto bad; /* ** Try to enable multicast (you would have thought ** promiscuous would be sufficient). (Skip if using ** HP-UX or SINIX) */ #if !defined(__hpux) && !defined(sinix) if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 || dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0) fprintf(stderr, "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf); #endif } /* ** Try to enable sap (when not in promiscuous mode when using ** using HP-UX and never under SINIX) */ #ifndef sinix if ( #ifdef __hpux !promisc && #endif (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 || dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) { /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ if (promisc) fprintf(stderr, "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf); else goto bad; } #endif /* ** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous ** options) */ #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20) if (dlbindreq(p->fd, 0, ebuf) < 0 || dlbindack(p->fd, (char *)buf, ebuf) < 0) goto bad; #endif /* ** Determine link type */ if (dlinforeq(p->fd, ebuf) < 0 || dlinfoack(p->fd, (char *)buf, ebuf) < 0) goto bad; infop = &((union DL_primitives *)buf)->info_ack; switch (infop->dl_mac_type) { case DL_CSMACD: case DL_ETHER: p->linktype = DLT_EN10MB; p->offset = 2; break; case DL_FDDI: p->linktype = DLT_FDDI; p->offset = 3; break; default: sprintf(ebuf, "unknown mac type 0x%lu", infop->dl_mac_type); goto bad; } #ifdef DLIOCRAW /* ** This is a non standard SunOS hack to get the ethernet header. */ if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { sprintf(ebuf, "DLIOCRAW: %s", pcap_strerror(errno)); goto bad; } #endif #ifdef HAVE_SYS_BUFMOD_H /* ** Another non standard call to get the data nicely buffered */ if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { sprintf(ebuf, "I_PUSH bufmod: %s", pcap_strerror(errno)); goto bad; } /* ** Now that the bufmod is pushed lets configure it. ** ** There is a bug in bufmod(7). When dealing with messages of ** less than snaplen size it strips data from the beginning not ** the end. ** ** This bug is supposed to be fixed in 5.3.2. Also, there is a ** patch available. Ask for bugid 1149065. */ ss = snaplen; #ifdef HAVE_SOLARIS release = get_release(&osmajor, &osminor, &osmicro); if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && getenv("BUFMOD_FIXED") == NULL) { fprintf(stderr, "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n", release); ss = 0; } #endif if (ss > 0 && strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { sprintf(ebuf, "SBIOCSSNAP: %s", pcap_strerror(errno)); goto bad; } /* ** Set up the bufmod flags */ if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) { sprintf(ebuf, "SBIOCGFLAGS: %s", pcap_strerror(errno)); goto bad; } flag |= SB_NO_DROPS; if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) { sprintf(ebuf, "SBIOCSFLAGS: %s", pcap_strerror(errno)); goto bad; } /* ** Set up the bufmod timeout */ if (to_ms != 0) { struct timeval to; to.tv_sec = to_ms / 1000; to.tv_usec = (to_ms * 1000) % 1000000; if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { sprintf(ebuf, "SBIOCSTIME: %s", pcap_strerror(errno)); goto bad; } } #endif /* ** As the last operation flush the read side. */ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { sprintf(ebuf, "FLUSHR: %s", pcap_strerror(errno)); goto bad; } /* Allocate data buffer */ p->bufsize = MAXDLBUF * sizeof(bpf_u_int32); p->buffer = (u_char *)malloc(p->bufsize + p->offset); return (p); bad: free(p); return (NULL); }
/********************************************************************** *%FUNCTION: openInterface *%ARGUMENTS: * ifname -- name of interface * type -- Ethernet frame type * hwaddr -- if non-NULL, set to the hardware address *%RETURNS: * A raw socket for talking to the Ethernet card. Exits on error. *%DESCRIPTION: * Opens a raw Ethernet socket ***********************************************************************/ int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { int fd; long buf[MAXDLBUF]; union DL_primitives *dlp; char base_dev[PATH_MAX]; int ppa; if(strlen(ifname) > PATH_MAX) { rp_fatal("socket: Interface name too long"); } if (strlen(ifname) < 2) { rp_fatal("socket: Interface name too short"); } ppa = atoi(&ifname[strlen(ifname)-1]); strncpy(base_dev, ifname, PATH_MAX); base_dev[strlen(base_dev)-1] = '\0'; /* rearranged order of DLPI code - delphys 20010803 */ dlp = (union DL_primitives*) buf; if ( (fd = open(base_dev, O_RDWR)) < 0) { /* Give a more helpful message for the common error case */ if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } /* Common error is to omit /dev/ */ if (errno == ENOENT) { char ifname[512]; snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev); if ((fd = open(ifname, O_RDWR)) < 0) { if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } } } } if (fd < 0) { fatalSys("socket"); } /* rearranged order of DLPI code - delphys 20010803 */ dlattachreq(fd, ppa); dlokack(fd, (char *)buf); dlbindreq(fd, type, 0, DL_CLDLS, 0, 0); dlbindack(fd, (char *)buf); dlinforeq(fd); dlinfoack(fd, (char *)buf); dl_abssaplen = ABS(dlp->info_ack.dl_sap_length); dl_saplen = dlp->info_ack.dl_sap_length; if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen)) fatalSys("invalid destination physical address length"); dl_addrlen = dl_abssaplen + ETHERADDRL; /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */ memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL); if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { fatalSys("DLIOCRAW"); } if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH"); return fd; }