📄 cdp.c
字号:
/* * $Id: cdp.c,v 1.5 2005/07/21 10:57:05 mchapman Exp $ */#include <system.h>#include <encoding.h>#if HAVE_SYS_TIME_H# include <sys/time.h>#endif /* HAVE_SYS_TIME_H */#if HAVE_SYS_SOCKET_H# include <sys/socket.h>#endif /* HAVE_SYS_SOCKET_H */#if HAVE_NET_IF_H# include <net/if.h>#endif /* HAVE_NET_IF_H */#if HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif /* HAVE_SYS_IOCTL_H */#if HAVE_LINUX_ETHTOOL_H# include <linux/ethtool.h>#endif /* HAVE_LINUX_ETHTOOL_H */#if HAVE_LINUX_SOCKIOS_H# include <linux/sockios.h>#endif /* HAVE_LINUX_ETHTOOL_H */#if HAVE_NETINET_IF_ETHER_H# include <netinet/if_ether.h>#endif /* HAVE_NETINET_IF_ETHER_H */#if HAVE_FCNTL_H# include <fcntl.h>#endif /* HAVE_FCNTL_H */#if HAVE_MULTICAST# if HAVE_NETPACKET_PACKET_H# include <netpacket/packet.h># endif /* HAVE_NETPACKET_PACKET_H */#endif /* HAVE_MULTICAST */#define BPF_FILTER "ether host 01:00:0c:cc:cc:cc and ether[20:2] = 0x2000"static const uint8_t cdp_multicast_mac[] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };static void_cdp_callback(cdp_t *cdp, const struct pcap_pkthdr *header, const void *data) { /* * Grab the header and data and save it in the supplied cdp object. * cdp_recv will pick it up when pcap_dispatch returns. */ cdp->header = header; cdp->data = data;}#if HAVE_MULTICASTstatic int_cdp_multicast(const cdp_t *cdp, int add) { int result; struct ifreq ifr; struct packet_mreq mreq; if (!cdp->pcap) return -1; memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifr.ifr_name, cdp->port, sizeof ifr.ifr_name - 1); ifr.ifr_name[sizeof ifr.ifr_name - 1] = '\0'; result = ioctl(pcap_fileno(cdp->pcap), SIOCGIFINDEX, &ifr); if (result < 0) return result; mreq.mr_ifindex = ifr.ifr_ifindex; mreq.mr_type = PACKET_MR_MULTICAST; mreq.mr_alen = 6; memcpy(mreq.mr_address, cdp_multicast_mac, 6); mreq.mr_address[6] = mreq.mr_address[7] = '\0'; return setsockopt( pcap_fileno(cdp->pcap), SOL_PACKET, add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, &mreq, sizeof(struct packet_mreq) );}#else /* HAVE_MULTICAST */static int _cdp_multicast(const cdp_t *cdp, int add) { return 1; }#endif /* ! HAVE_MULTICAST */#if HAVE_LINUX_ETHTOOL_Hstatic void_cdp_duplex(cdp_t *cdp) { int result, fd; struct ifreq ifr; struct ethtool_cmd ecmd; if (cdp->flags & CDP_DISABLE_SEND) { fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return; } else fd = libnet_getfd(cdp->libnet); memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifr.ifr_name, cdp->port, sizeof ifr.ifr_name - 1); ifr.ifr_name[sizeof ifr.ifr_name - 1] = '\0'; ifr.ifr_data = (caddr_t)&ecmd; ecmd.cmd = ETHTOOL_GSET; result = ioctl(fd, SIOCETHTOOL, &ifr); if (result >= 0) NEW(cdp->duplex, ecmd.duplex == DUPLEX_FULL ? 1 : 0, uint8_t); if (cdp->flags & CDP_DISABLE_SEND) close(fd);}#endif /* HAVE_LINUX_ETHTOOL_H */cdp_llist_t *cdp_get_ports(char *errors) { /* This code is lifted from Ethereal 0.9.13 */ char *pcap_errors, *libnet_errors; int sock; int len, lastlen; struct ifconf ifc; struct ifreq ifrflags, *ifr, *last; char *buf; pcap_t *pcap; libnet_t *libnet; cdp_llist_t *normal, *loopback; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errors, (CDP_ERRBUF_SIZE - 1) * sizeof(char), "Error opening socket: %s", strerror(errno)); errors[CDP_ERRBUF_SIZE - 1] = '\0'; return NULL; } lastlen = 0; len = 100 * sizeof(struct ifreq); for ( ; ; ) { buf = MALLOC(len, char); ifc.ifc_len = len; ifc.ifc_buf = buf; memset(buf, 0, len); if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) { snprintf(errors, (CDP_ERRBUF_SIZE - 1) * sizeof(char), "Could not get list of interfaces: %s", strerror(errno)); errors[CDP_ERRBUF_SIZE - 1] = '\0'; FREE(buf); close(sock); return NULL; } } else { if ((unsigned) ifc.ifc_len < sizeof(struct ifreq)) { sprintf(errors, "SIOCGIFCONF ioctl returned an invalid buffer"); FREE(buf); close(sock); return NULL; } if (ifc.ifc_len == lastlen) break; lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); FREE(buf); } normal = cdp_llist_new((cdp_dup_fn_t)strdup, (cdp_free_fn_t)free); loopback = cdp_llist_new((cdp_dup_fn_t)strdup, (cdp_free_fn_t)free); pcap_errors = SALLOC(PCAP_ERRBUF_SIZE); libnet_errors = SALLOC(LIBNET_ERRBUF_SIZE); ifr = (struct ifreq *)ifc.ifc_req; last = (struct ifreq *)VOIDP_OFFSET(ifr, ifc.ifc_len); for ( ; ifr < last; ifr++) { cdp_llist_iter_t found; /* * Skip addresses that begin with "dummy", or that include * a ":" (the latter are Solaris virtuals). */ if (strncmp(ifr->ifr_name, "dummy", 5) == 0 || strchr(ifr->ifr_name, ':') != NULL) continue; /* * If we already have this interface name on the list, * don't add it (SIOCGIFCONF returns, at least on * BSD-flavored systems, one entry per interface *address*; * if an interface has multiple addresses, we get multiple * entries for it). */ for ( found = cdp_llist_iter(normal); found && strcmp( (char *)cdp_llist_get(found), ifr->ifr_name ); found = cdp_llist_next(found) ) ; if (found) continue; for ( found = cdp_llist_iter(loopback); found && strcmp( (char *)cdp_llist_get(found), ifr->ifr_name ); found = cdp_llist_next(found) ) ; if (found) continue; /* * Get the interface flags. */ memset(&ifrflags, 0, sizeof ifrflags); strncpy(ifrflags.ifr_name, ifr->ifr_name, sizeof ifrflags.ifr_name); if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { if (errno == ENXIO) continue; snprintf(errors, (CDP_ERRBUF_SIZE - 1) * sizeof(char), "Could not get flags for interface %s: %s", ifr->ifr_name, strerror(errno)); errors[CDP_ERRBUF_SIZE - 1] = '\0'; FREE(buf); close(sock); FREE(pcap_errors); FREE(libnet_errors); cdp_llist_free(normal); cdp_llist_free(loopback); return NULL; } /* * Skip interfaces that aren't up. */ if (!(ifrflags.ifr_flags & IFF_UP)) continue; /* * Skip interfaces that we can't open with "libpcap". * Open with the minimum packet size - it appears that the * IRIX SIOCSNOOPLEN "ioctl" may fail if the capture length * supplied is too large, rather than just truncating it. * Also grab the data link type here. */ if (!(pcap = pcap_open_live(ifr->ifr_name, 68, 0, 0, pcap_errors))) continue; { int linktype = pcap_datalink(pcap); pcap_close(pcap); /* * Skip interfaces where we can't use ethernet addresses. */ if (!(linktype == DLT_EN10MB || linktype == DLT_FDDI || linktype == DLT_IEEE802)) continue; } /* * Also skip interfaces that we can't be open with "libnet". * Some versions of libnet don't work with loopback interfaces. */ if (!(libnet = libnet_init(LIBNET_LINK, ifr->ifr_name, libnet_errors))) continue; libnet_destroy(libnet); /* * If it's a loopback interface, add it to the loopback list, * otherwise add it after the normal list. */ { char *port = strdup(ifr->ifr_name); if ((ifrflags.ifr_flags & IFF_LOOPBACK) || strncmp(ifr->ifr_name, "lo", 2) == 0) cdp_llist_append(loopback, port); else cdp_llist_append(normal, port); } } FREE(buf); close(sock); FREE(pcap_errors); FREE(libnet_errors); cdp_llist_transfer(normal, loopback); cdp_llist_free(loopback); return normal;}cdp_t *cdp_new(const char *port, int flags, char *errors) { cdp_t *cdp; char *pcap_errors; char *libnet_errors; bpf_u_int32 mask; bpf_u_int32 net; struct bpf_program filter; struct libnet_ether_addr *hwaddr; pcap_errors = SALLOC(PCAP_ERRBUF_SIZE); libnet_errors = SALLOC(LIBNET_ERRBUF_SIZE); errors[0] = '\0'; cdp = CALLOC(1, cdp_t); cdp->flags = flags; { int sock; struct ifreq ifrflags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -