END_TEST START_TEST(test_intf_get) { struct intf_entry ifent; intf_t *i; i = intf_open(); memset(&ifent, 0, sizeof(ifent)); fail_unless(intf_get(i, &ifent) < 0, "didn't fail on empty request"); ifent.intf_len = sizeof(ifent); fail_unless(intf_get(i, &ifent) < 0, "didn't fail on empty name"); intf_close(i); }
void open_devices(void) { i = intf_open(); if ( i == NULL ) { perror("intf open error"); exit(-1); } strncpy(ie.intf_name, iface, 60); if ( intf_get(i, &ie) == -1 ) { perror("intf get error"); exit(-1); } mha = ie.intf_link_addr; if ( addr_ntop(&mha, mhw, 32) == NULL ){ exit(-1); } mad = ie.intf_addr; if ( addr_ntop(&mad, mip, 32) == NULL ){ exit(-1); } rmslash(mip); e = eth_open(iface); if ( e == NULL ) { perror("eth open error"); exit(-1); } p = pcap_open_live(iface, 20000, 1, 500, ebuf); if ( p == NULL ) { perror(ebuf); exit(-1); } }
/** * Plug an object interface into a new destination object interface * * @v intf Object interface * @v dest New destination object interface * * The reference to the existing destination interface is dropped, a * reference to the new destination interface is obtained, and the * interface is updated to point to the new destination interface. * * Note that there is no "unplug" call; instead you must plug the * interface into a null interface. */ void intf_plug ( struct interface *intf, struct interface *dest ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n", INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) ); intf_get ( dest ); intf_put ( intf->dest ); intf->dest = dest; }
static void arpd_init(char *dev, int naddresses, char **addresses) { struct bpf_program fcode; char filter[1024], ebuf[PCAP_ERRBUF_SIZE], *dst; intf_t *intf; dst = arpd_expandips(naddresses, addresses); if ((arpd_arp = arp_open()) == NULL) err(1, "arp_open"); if ((intf = intf_open()) == NULL) err(1, "intf_open"); if (dev == NULL) { if ((dev = pcap_lookupdev(ebuf)) == NULL) errx(1, "pcap_lookupdev: %s", ebuf); } arpd_ifent.intf_len = sizeof(arpd_ifent); strncpy(arpd_ifent.intf_name, dev, sizeof(arpd_ifent.intf_name) - 1); arpd_ifent.intf_name[sizeof(arpd_ifent.intf_name) - 1] = '\0'; if (intf_get(intf, &arpd_ifent) < 0) err(1, "intf_get"); if (arpd_ifent.intf_addr.addr_type != ADDR_TYPE_IP || arpd_ifent.intf_link_addr.addr_type != ADDR_TYPE_ETH) errx(1, "bad interface configuration: not IP or Ethernet"); arpd_ifent.intf_addr.addr_bits = IP_ADDR_BITS; snprintf(filter, sizeof(filter), "arp %s%s%s and not ether src %s", dst ? "and (" : "", dst ? dst : "", dst ? ")" : "", addr_ntoa(&arpd_ifent.intf_link_addr)); if ((arpd_pcap = pcap_open_live(dev, 128, 0, 500, ebuf)) == NULL) errx(1, "pcap_open_live: %s", ebuf); if (pcap_compile(arpd_pcap, &fcode, filter, 1, 0) < 0 || pcap_setfilter(arpd_pcap, &fcode) < 0) errx(1, "bad pcap filter: %s", pcap_geterr(arpd_pcap)); #if defined(BSD) && defined(BIOCIMMEDIATE) { int on = 1; if (ioctl(pcap_fileno(arpd_pcap), BIOCIMMEDIATE, &on) < 0) err(1, "BIOCIMMEDIATE"); } #endif if ((arpd_eth = eth_open(dev)) == NULL) errx(1, "eth_open"); #ifndef LOG_PERROR #define LOG_PERROR 0 #endif openlog("arpd", LOG_PERROR|LOG_PID|LOG_CONS, LOG_DAEMON); syslog(LOG_INFO, "listening on %s: %s", dev, filter); }
eth_t * eth_open(const char *device) { eth_t *eth; intf_t *intf; struct intf_entry ifent; eth_addr_t ea; char *p, *buf; ULONG len; /* Get interface entry. */ memset(&ifent, 0, sizeof(ifent)); if ((intf = intf_open()) != NULL) { strlcpy(ifent.intf_name, device, sizeof(ifent.intf_name)); intf_get(intf, &ifent); intf_close(intf); } if (ifent.intf_link_addr.addr_type != ADDR_TYPE_ETH) return (NULL); /* Get Packet driver adapter name/desc lists. */ buf = NULL; PacketGetAdapterNames(buf, &len); if (len > 0 && (buf = malloc(len)) != NULL) { if (!PacketGetAdapterNames(buf, &len)) { free(buf); buf = NULL; } } if (buf == NULL) return (NULL); /* XXX - find adapter with matching interface MAC address. */ if ((eth = calloc(1, sizeof(*eth))) == NULL) { free(buf); return (NULL); } for (p = buf; *p != '\0'; p += strlen(p) + 1) { if ((eth->lpa = PacketOpenAdapter(p)) != NULL) { if (eth->lpa->hFile != INVALID_HANDLE_VALUE && eth_get(eth, &ea) == 0 && memcmp(&ea, &ifent.intf_link_addr.addr_eth, ETH_ADDR_LEN) == 0) { PacketSetBuff(eth->lpa, 512000); eth->pkt = PacketAllocatePacket(); break; } PacketCloseAdapter(eth->lpa); } } free(buf); if (eth->pkt == NULL) eth = eth_close(eth); return (eth); }
/* Converts a dnet interface name (ifname) to its pcap equivalent, which is stored in pcapdev (up to a length of pcapdevlen). Returns 0 and fills in pcapdev if successful. */ int eth_get_pcap_devname(const char *ifname, char *pcapdev, int pcapdevlen) { intf_t *intf; struct intf_entry ie; pcap_if_t *pcapdevs; pcap_if_t *pdev; char pname[128]; if ((intf = intf_open()) == NULL) return -1; pname[0] = '\0'; memset(&ie, 0, sizeof(ie)); strlcpy(ie.intf_name, ifname, sizeof(ie.intf_name)); if (intf_get(intf, &ie) != 0) { intf_close(intf); return -1; } intf_close(intf); /* Next we must find the pcap device name corresponding to the device. The device description used to be compared with those from PacketGetAdapterNames(), but that was unrelaible because dnet and pcap sometimes give different descriptions. For example, dnet gave me "AMD PCNET Family PCI Ethernet Adapter - Packet Scheduler Miniport" for one of my adapters (in vmware), while pcap described it as "VMware Accelerated AMD PCNet Adapter (Microsoft's Packet Scheduler)". Then IP addresses used to be compared, but that proved to be unreliable as well. Now we compare hardware addresses much like eth_open() does */ if (pcap_findalldevs(&pcapdevs, NULL) == -1) return -1; if (pname[0] == '\0' && ie.intf_link_addr.addr_type == ADDR_TYPE_ETH) { for(pdev=pcapdevs; pdev && !pname[0]; pdev = pdev->next) { eth_t eth; eth_addr_t ea; eth.lpa = PacketOpenAdapter(pdev->name); if (eth.lpa == NULL) continue; if (eth.lpa->hFile != INVALID_HANDLE_VALUE && eth_get(ð, &ea) == 0 && memcmp(&ea, &ie.intf_link_addr.addr_eth, ETH_ADDR_LEN) == 0) { /* Found it -- Yay! */ strlcpy(pname, pdev->name, sizeof(pname)); } PacketCloseAdapter(eth.lpa); } } pcap_freealldevs(pcapdevs); if (pname[0]) { strlcpy(pcapdev, pname, pcapdevlen); return 0; } return -1; }
tun_t * tun_open(struct addr *src, struct addr *dst, int mtu) { struct intf_entry ifent; tun_t *tun; char dev[128]; int i; if (src->addr_type != ADDR_TYPE_IP || dst->addr_type != ADDR_TYPE_IP || src->addr_bits != IP_ADDR_BITS || dst->addr_bits != IP_ADDR_BITS) { errno = EINVAL; return (NULL); } if ((tun = calloc(1, sizeof(*tun))) == NULL) return (NULL); if ((tun->intf = intf_open()) == NULL) return (tun_close(tun)); memset(&ifent, 0, sizeof(ifent)); ifent.intf_len = sizeof(ifent); for (i = 0; i < MAX_DEVS; i++) { snprintf(dev, sizeof(dev), "/dev/tun%d", i); strlcpy(ifent.intf_name, dev + 5, sizeof(ifent.intf_name)); tun->save = ifent; if ((tun->fd = open(dev, O_RDWR, 0)) != -1 && intf_get(tun->intf, &tun->save) == 0) { route_t *r; struct route_entry entry; ifent.intf_flags = INTF_FLAG_UP|INTF_FLAG_POINTOPOINT; ifent.intf_addr = *src; ifent.intf_dst_addr = *dst; ifent.intf_mtu = mtu; if (intf_set(tun->intf, &ifent) < 0) tun = tun_close(tun); /* XXX - try to ensure our route got set */ if ((r = route_open()) != NULL) { entry.route_dst = *dst; entry.route_gw = *src; route_add(r, &entry); route_close(r); } break; } } if (i == MAX_DEVS) tun = tun_close(tun); return (tun); }
/* Look up an interface from an index, such as a sockaddr_in6.sin6_scope_id. */ int intf_get_index(intf_t *intf, struct intf_entry *entry, int af, unsigned int index) { char namebuf[IFNAMSIZ]; char *devname; /* af is ignored; only used in intf-win32.c. */ devname = if_indextoname(index, namebuf); if (devname == NULL) return (-1); strlcpy(entry->intf_name, devname, sizeof(entry->intf_name)); return intf_get(intf, entry); }
/** * Get object interface destination and operation method (without pass-through) * * @v intf Object interface * @v type Operation type * @ret dest Destination interface * @ret func Implementing method, or NULL */ void * intf_get_dest_op_no_passthru_untyped ( struct interface *intf, void *type, struct interface **dest ) { struct interface_descriptor *desc; struct interface_operation *op; unsigned int i; *dest = intf_get ( intf->dest ); desc = (*dest)->desc; for ( i = desc->num_op, op = desc->op ; i ; i--, op++ ) { if ( op->type == type ) return op->func; } return NULL; }
int intf_set(intf_t *intf, const struct intf_entry *entry) { struct ifreq ifr; struct intf_entry *orig; struct addr bcast; u_char buf[BUFSIZ]; orig = (struct intf_entry *)buf; orig->intf_len = sizeof(buf); strcpy(orig->intf_name, entry->intf_name); if (intf_get(intf, orig) < 0) return (-1); /* Delete any existing aliases. */ if (_intf_delete_aliases(intf, orig) < 0) return (-1); /* Delete any existing addrs. */ if (_intf_delete_addrs(intf, orig) < 0) return (-1); memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); /* Set interface MTU. */ if (entry->intf_mtu != 0) { ifr.ifr_mtu = entry->intf_mtu; #ifdef SIOCSIFMTU if (ioctl(intf->fd, SIOCSIFMTU, &ifr) < 0) #endif return (-1); } /* Set interface address. */ if (entry->intf_addr.addr_type == ADDR_TYPE_IP) { #ifdef BSD /* XXX - why must this happen before SIOCSIFADDR? */ if (addr_btos(entry->intf_addr.addr_bits, &ifr.ifr_addr) == 0) { if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0) return (-1); } #endif if (addr_ntos(&entry->intf_addr, &ifr.ifr_addr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0 && errno != EEXIST) return (-1); if (addr_btos(entry->intf_addr.addr_bits, &ifr.ifr_addr) == 0 #ifdef __linux__ && entry->intf_addr.addr_ip != 0 #endif ) { if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0) return (-1); } if (addr_bcast(&entry->intf_addr, &bcast) == 0) { if (addr_ntos(&bcast, &ifr.ifr_broadaddr) == 0) { /* XXX - ignore error from non-broadcast ifs */ ioctl(intf->fd, SIOCSIFBRDADDR, &ifr); } } } /* Set link-level address. */ if (entry->intf_link_addr.addr_type == ADDR_TYPE_ETH && addr_cmp(&entry->intf_link_addr, &orig->intf_link_addr) != 0) { #if defined(SIOCSIFHWADDR) if (addr_ntos(&entry->intf_link_addr, &ifr.ifr_hwaddr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFHWADDR, &ifr) < 0) return (-1); #elif defined (SIOCSIFLLADDR) memcpy(ifr.ifr_addr.sa_data, &entry->intf_link_addr.addr_eth, ETH_ADDR_LEN); ifr.ifr_addr.sa_len = ETH_ADDR_LEN; if (ioctl(intf->fd, SIOCSIFLLADDR, &ifr) < 0) return (-1); #else eth_t *eth; if ((eth = eth_open(entry->intf_name)) == NULL) return (-1); if (eth_set(eth, &entry->intf_link_addr.addr_eth) < 0) { eth_close(eth); return (-1); } eth_close(eth); #endif } /* Set point-to-point destination. */ if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) { if (addr_ntos(&entry->intf_dst_addr, &ifr.ifr_dstaddr) < 0) return (-1); if (ioctl(intf->fd, SIOCSIFDSTADDR, &ifr) < 0 && errno != EEXIST) return (-1); } /* Add aliases. */ if (_intf_add_aliases(intf, entry) < 0) return (-1); /* Set interface flags. */ if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0) return (-1); ifr.ifr_flags = intf_flags_to_iff(entry->intf_flags, ifr.ifr_flags); if (ioctl(intf->fd, SIOCSIFFLAGS, &ifr) < 0) return (-1); return (0); }
int intf_main(int argc, char *argv[]) { struct intf_entry *entry; struct addr *ap, addr; char *cmd, buf[1024]; if (argc < 2) usage(); cmd = argv[1]; entry = (struct intf_entry *)buf; memset(entry, 0, sizeof(*entry)); entry->intf_len = sizeof(buf); if ((intf = intf_open()) == NULL) err(1, "intf_open"); if (strcmp(cmd, "show") == 0) { if (intf_loop(intf, print_intf, NULL) < 0) err(1, "intf_loop"); } else if (strcmp(cmd, "get") == 0) { if (argc < 3) usage(); strlcpy(entry->intf_name, argv[2], sizeof(entry->intf_name)); if (intf_get(intf, entry) < 0) err(1, "intf_get"); print_intf(entry, NULL); } else if (strcmp(cmd, "src") == 0) { if (argc < 3 || addr_aton(argv[2], &addr) < 0) usage(); if (intf_get_src(intf, entry, &addr) < 0) err(1, "intf_get_src"); print_intf(entry, NULL); } else if (strcmp(cmd, "dst") == 0) { if (argc < 3 || addr_aton(argv[2], &addr) < 0) usage(); if (intf_get_dst(intf, entry, &addr) < 0) err(1, "intf_get_dst"); print_intf(entry, NULL); } else if (strcmp(cmd, "set") == 0) { if (argc < 4) usage(); strlcpy(entry->intf_name, argv[2], sizeof(entry->intf_name)); for (argv += 3, argc -= 3; argc > 1; argv += 2, argc -= 2) { if (strcmp(argv[0], "alias") == 0) { ap = &entry->intf_alias_addrs [entry->intf_alias_num++]; } else if (strcmp(argv[0], "dst") == 0) { ap = &entry->intf_dst_addr; } else if (strcmp(argv[0], "inet") == 0) { ap = &entry->intf_addr; } else if (strcmp(argv[0], "link") == 0) { ap = &entry->intf_link_addr; } else break; if (addr_pton(argv[1], ap) < 0) err(1, "invalid address: %s", argv[1]); } for ( ; argc > 0; argv++, argc--) { if (strcmp(argv[0], "up") == 0) entry->intf_flags |= INTF_FLAG_UP; else if (strcmp(argv[0], "down") == 0) entry->intf_flags &= ~INTF_FLAG_UP; else if (strcmp(argv[0], "arp") == 0) entry->intf_flags &= ~INTF_FLAG_NOARP; else if (strcmp(argv[0], "noarp") == 0) entry->intf_flags |= INTF_FLAG_NOARP; else usage(); } if (intf_set(intf, entry) < 0) err(1, "intf_set"); } else usage(); intf_close(intf); exit(0); }
/* Converts a dnet interface name (ifname) to its pcap equivalent, which is stored in pcapdev (up to a length of pcapdevlen). Returns 0 and fills in pcapdev if successful. */ int intf_get_pcap_devname(const char *ifname, char *pcapdev, int pcapdevlen) { int i; intf_t *intf; struct intf_entry ie; pcap_if_t *pcapdevs; pcap_if_t *pdev; char pname[128]; struct sockaddr_in devip; pcap_addr_t *pa; if ((intf = intf_open()) == NULL) return -1; pname[0] = '\0'; memset(&ie, 0, sizeof(ie)); strlcpy(ie.intf_name, ifname, sizeof(ie.intf_name)); if (intf_get(intf, &ie) != 0) { intf_close(intf); return -1; } intf_close(intf); /* Find the first IPv4 address for ie */ if (ie.intf_addr.addr_type == ADDR_TYPE_IP) { addr_ntos(&ie.intf_addr, (struct sockaddr *) &devip); } else { for(i=0; i < (int) ie.intf_alias_num; i++) { if (ie.intf_alias_addrs[i].addr_type == ADDR_TYPE_IP) { addr_ntos(&ie.intf_alias_addrs[i], (struct sockaddr *) &devip); break; } } if (i == ie.intf_alias_num) return -1; // Failed to find IPv4 address, which is currently a requirement } /* Next we must find the pcap device name corresponding to the device. The device description used to be compared with those from PacketGetAdapterNames(), but that was unrelaible because dnet and pcap sometimes give different descriptions. For example, dnet gave me "AMD PCNET Family PCI Ethernet Adapter - Packet Scheduler Miniport" for one of my adapters (in vmware), while pcap described it as "VMware Accelerated AMD PCNet Adapter (Microsoft's Packet Scheduler)". Plus, Packet* functions aren't really supported for external use by the WinPcap folks. So I have rewritten this to compare interface addresses (which has its own problems -- what if you want to listen an an interface with no IP address set?) --Fyodor */ if (pcap_findalldevs(&pcapdevs, NULL) == -1) return -1; for(pdev=pcapdevs; pdev && !pname[0]; pdev = pdev->next) { for (pa=pdev->addresses; pa && !pname[0]; pa = pa->next) { if (pa->addr->sa_family != AF_INET) continue; if (((struct sockaddr_in *)pa->addr)->sin_addr.s_addr == devip.sin_addr.s_addr) { strlcpy(pname, pdev->name, sizeof(pname)); /* Found it -- Yay! */ break; } } } pcap_freealldevs(pcapdevs); if (pname[0]) { strlcpy(pcapdev, pname, pcapdevlen); return 0; } return -1; }