version 1.1, 2013/06/25 09:08:10
|
version 1.1.2.1, 2013/06/25 09:08:10
|
Line 0
|
Line 1
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <fcntl.h> |
|
#include <unistd.h> |
|
#include <string.h> |
|
#include <errno.h> |
|
#include <poll.h> |
|
#include <getopt.h> |
|
#include <pthread.h> |
|
#include <assert.h> |
|
#include <sys/types.h> |
|
#include <sys/param.h> |
|
#include <sys/limits.h> |
|
#include <sys/socket.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/mman.h> |
|
#include <net/if.h> |
|
#include <net/bpf.h> |
|
#include <machine/atomic.h> |
|
|
|
#ifdef __FreeBSD__ |
|
#include <net/ethernet.h> |
|
#endif |
|
#ifdef __OpenBSD__ |
|
#include <net/ethertypes.h> |
|
#include <netinet/in_systm.h> |
|
#endif |
|
#include <net/if_arp.h> |
|
#include <netinet/in.h> |
|
#include <netinet/ip.h> |
|
#include <netinet/ip6.h> |
|
#include <netinet/udp.h> |
|
#include <netinet/tcp.h> |
|
#include <netinet/ip_icmp.h> |
|
#include <arpa/inet.h> |
|
#ifdef __OpenBSD__ |
|
#include <netinet/if_ether.h> |
|
#endif |
|
|
|
#ifndef roundup |
|
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) /* to any y */ |
|
#endif |
|
|
|
#define time_spec_sub(vvp, uvp) \ |
|
do { \ |
|
(vvp)->tv_sec -= (uvp)->tv_sec; \ |
|
(vvp)->tv_nsec -= (uvp)->tv_nsec; \ |
|
if ((vvp)->tv_nsec < 0) { \ |
|
(vvp)->tv_sec--; \ |
|
(vvp)->tv_nsec += 1000000000; \ |
|
} \ |
|
} while (0) |
|
|
|
|
|
int Verbose, flg; |
|
|
|
|
|
static void * |
|
ShowPkt(void *buffer) |
|
{ |
|
char Proto = 0, szStr[BUFSIZ], szLine[BUFSIZ], szWrk[BUFSIZ], szShow[USHRT_MAX] = { 0 }; |
|
struct bpf_hdr *bpf = buffer; |
|
#ifdef __FreeBSD__ |
|
struct bpf_zbuf_header *bzh = buffer; |
|
struct icmphdr *icmp; |
|
#endif |
|
#ifdef __OpenBSD__ |
|
struct icmp *icmp; |
|
#endif |
|
struct ether_header *eth; |
|
struct ip *ip; |
|
struct ip6_hdr *ipv6; |
|
struct arphdr *arp; |
|
struct udphdr *udp; |
|
struct tcphdr *tcp; |
|
|
|
assert(buffer); |
|
|
|
#ifdef __FreeBSD__ |
|
snprintf(szLine, BUFSIZ, "#Packet length: %d\n>>> Ethernet ...\n", flg ? bzh->bzh_kernel_len : bpf->bh_datalen); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
eth = (struct ether_header *) (buffer + (flg ? bzh->bzh_kernel_len : bpf->bh_hdrlen)); |
|
#else |
|
snprintf(szLine, BUFSIZ, "#Packet length: %d\n>>> Ethernet ...\n", bpf->bh_datalen); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
eth = (struct ether_header *) (buffer + bpf->bh_hdrlen); |
|
#endif |
|
|
|
switch (ntohs(eth->ether_type)) { |
|
case ETHERTYPE_ARP: |
|
strlcpy(szWrk, "(ARP)", sizeof szWrk); |
|
break; |
|
case ETHERTYPE_IP: |
|
strlcpy(szWrk, "(IP)", sizeof szWrk); |
|
break; |
|
case ETHERTYPE_IPV6: |
|
strlcpy(szWrk, "(IPv6)", sizeof szWrk); |
|
break; |
|
default: |
|
memset(szWrk, 0, sizeof szWrk); |
|
} |
|
snprintf(szStr, BUFSIZ, "%02x:%02x:%02x:%02x:%02x:%02x", eth->ether_shost[0], eth->ether_shost[1], |
|
eth->ether_shost[2], eth->ether_shost[3], eth->ether_shost[4], eth->ether_shost[5]); |
|
snprintf(szLine, BUFSIZ, "ether_type: %04x%s, src_mac: %s, ", ntohs(eth->ether_type), szWrk, szStr); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
snprintf(szStr, BUFSIZ, "%02x:%02x:%02x:%02x:%02x:%02x", eth->ether_dhost[0], eth->ether_dhost[1], |
|
eth->ether_dhost[2], eth->ether_dhost[3], eth->ether_dhost[4], eth->ether_dhost[5]); |
|
snprintf(szLine, BUFSIZ, "dst_mac: %s\n", szStr); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
|
|
switch (ntohs(eth->ether_type)) { |
|
case ETHERTYPE_ARP: |
|
arp = (struct arphdr*) (((caddr_t) eth) + ETHER_HDR_LEN); |
|
strlcat(szShow, "\t>>> ARP ...\n", USHRT_MAX); |
|
|
|
switch (ntohs(arp->ar_op)) { |
|
case ARPOP_REQUEST: |
|
strlcpy(szStr, "Request", sizeof szStr); |
|
break; |
|
case ARPOP_REPLY: |
|
strlcpy(szStr, "Reply", sizeof szStr); |
|
break; |
|
case ARPOP_REVREQUEST: |
|
strlcpy(szStr, "RevRequest", sizeof szStr); |
|
break; |
|
case ARPOP_REVREPLY: |
|
strlcpy(szStr, "RevReply", sizeof szStr); |
|
break; |
|
case ARPOP_INVREQUEST: |
|
strlcpy(szStr, "InvRequest", sizeof szStr); |
|
break; |
|
case ARPOP_INVREPLY: |
|
strlcpy(szStr, "InvReply", sizeof szStr); |
|
break; |
|
default: |
|
strlcpy(szStr, "*Unknown*", sizeof szStr); |
|
} |
|
snprintf(szLine, BUFSIZ, "\tAddr_fmt: %d, Proto_fmt: %d, Addr_len: %d, Proto_len: %d, %s\n", |
|
ntohs(arp->ar_hrd), ntohs(arp->ar_pro), arp->ar_hln, arp->ar_pln, szStr); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
break; |
|
case ETHERTYPE_IP: |
|
ip = (struct ip*) (((caddr_t) eth) + ETHER_HDR_LEN); |
|
strlcat(szShow, "\t>>> IP ...\n", USHRT_MAX); |
|
|
|
snprintf(szStr, BUFSIZ, "Frag_off: %d", ntohs(ip->ip_off) & IP_OFFMASK); |
|
if (ntohs(ip->ip_off) & IP_RF) |
|
strlcat(szStr, "|RF", sizeof szStr); |
|
if (ntohs(ip->ip_off) & IP_DF) |
|
strlcat(szStr, "|DF", sizeof szStr); |
|
if (ntohs(ip->ip_off) & IP_MF) |
|
strlcat(szStr, "|MF", sizeof szStr); |
|
snprintf(szLine, BUFSIZ, "\tTOS: %02x, TTL: %d, ID: %04x, Cksum: %04x, Len: %d, %s\n", |
|
ip->ip_tos, ip->ip_ttl, ntohs(ip->ip_id), ntohs(ip->ip_sum), |
|
ntohs(ip->ip_len), szStr); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
snprintf(szLine, BUFSIZ, "\tProto: %d, Src_addr: %s, Dst_addr: %s\n", |
|
ip->ip_p, inet_ntop(AF_INET, &ip->ip_src, szStr, BUFSIZ), |
|
inet_ntop(AF_INET, &ip->ip_dst, szWrk, BUFSIZ)); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
|
|
Proto = ip->ip_p; |
|
break; |
|
case ETHERTYPE_IPV6: |
|
ipv6 = (struct ip6_hdr*) (((caddr_t) eth) + ETHER_HDR_LEN); |
|
strlcat(szShow, "\t>>> IPv6 ...\n", USHRT_MAX); |
|
|
|
snprintf(szLine, BUFSIZ, "\tHLim: %d, Payload_len: %d, Flow: %u\n", ipv6->ip6_hlim, |
|
htons(ipv6->ip6_plen), htonl(ipv6->ip6_flow) & IPV6_FLOWLABEL_MASK); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
inet_ntop(AF_INET6, &ipv6->ip6_src, szStr, BUFSIZ); |
|
inet_ntop(AF_INET6, &ipv6->ip6_dst, szWrk, BUFSIZ); |
|
snprintf(szLine, BUFSIZ, "\tNext: %d, Src_addr: %s, Dst_addr: %s\n", ipv6->ip6_nxt, szStr, szWrk); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
|
|
Proto = ipv6->ip6_nxt; |
|
break; |
|
} |
|
|
|
if (Proto && (ntohs(eth->ether_type) == ETHERTYPE_IP || ntohs(eth->ether_type) == ETHERTYPE_IPV6)) |
|
switch (Proto) { |
|
case IPPROTO_TCP: |
|
strlcat(szShow, "\t\t>>> TCP ...\n", USHRT_MAX); |
|
if (ntohs(eth->ether_type) == ETHERTYPE_IPV6) |
|
tcp = (struct tcphdr*) (((caddr_t) ipv6) + sizeof(struct ip6_hdr)); |
|
else |
|
tcp = (struct tcphdr*) (((caddr_t) ip) + sizeof(struct ip)); |
|
|
|
snprintf(szLine, BUFSIZ, "\t\tsrc_port: %d, dst_port: %d, seq: %u, ack: %u\n", |
|
ntohs(tcp->th_sport), ntohs(tcp->th_dport), tcp->th_seq, tcp->th_ack); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
snprintf(szWrk, BUFSIZ, "%d", (u_char) tcp->th_off >> 4); |
|
if (tcp->th_flags & TH_FIN) |
|
strlcat(szWrk, "|FIN", sizeof szWrk); |
|
if (tcp->th_flags & TH_SYN) |
|
strlcat(szWrk, "|SYN", sizeof szWrk); |
|
if (tcp->th_flags & TH_RST) |
|
strlcat(szWrk, "|RST", sizeof szWrk); |
|
if (tcp->th_flags & TH_PUSH) |
|
strlcat(szWrk, "|PUSH", sizeof szWrk); |
|
if (tcp->th_flags & TH_ACK) |
|
strlcat(szWrk, "|ACK", sizeof szWrk); |
|
if (tcp->th_flags & TH_URG) |
|
strlcat(szWrk, "|URG", sizeof szWrk); |
|
if (tcp->th_flags & TH_ECE) |
|
strlcat(szWrk, "|ECE", sizeof szWrk); |
|
if (tcp->th_flags & TH_CWR) |
|
strlcat(szWrk, "|CWR", sizeof szWrk); |
|
snprintf(szLine, BUFSIZ, "\t\toff: %s, win: %d, urp: %04x, cksum: %04x\n", |
|
szWrk, ntohs(tcp->th_win), ntohs(tcp->th_urp), ntohs(tcp->th_sum)); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
break; |
|
case IPPROTO_UDP: |
|
strlcat(szShow, "\t\t>>> UDP ...\n", USHRT_MAX); |
|
if (ntohs(eth->ether_type) == ETHERTYPE_IPV6) |
|
udp = (struct udphdr*) (((caddr_t) ipv6) + sizeof(struct ip6_hdr)); |
|
else |
|
udp = (struct udphdr*) (((caddr_t) ip) + sizeof(struct ip)); |
|
|
|
snprintf(szLine, BUFSIZ, "\t\tsrc_port: %d, dst_port: %d, len: %d, cksum: %04x\n", |
|
ntohs(udp->uh_sport), ntohs(udp->uh_dport), |
|
ntohs(udp->uh_ulen), ntohs(udp->uh_sum)); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
break; |
|
case IPPROTO_ICMP: |
|
strlcat(szShow, "\t\t>>> ICMP ...\n", USHRT_MAX); |
|
#ifdef __FreeBSD__ |
|
if (ntohs(eth->ether_type) == ETHERTYPE_IPV6) |
|
icmp = (struct icmphdr*) (((caddr_t) ipv6) + sizeof(struct ip6_hdr)); |
|
else |
|
icmp = (struct icmphdr*) (((caddr_t) ip) + sizeof(struct ip)); |
|
#endif |
|
#ifdef __OpenBSD__ |
|
if (ntohs(eth->ether_type) == ETHERTYPE_IPV6) |
|
icmp = (struct icmp*) (((caddr_t) ipv6) + sizeof(struct ip6_hdr)); |
|
else |
|
icmp = (struct icmp*) (((caddr_t) ip) + sizeof(struct ip)); |
|
#endif |
|
|
|
snprintf(szLine, BUFSIZ, "\t\ttype: %d, code: %d: cksum: %04x\n", |
|
icmp->icmp_type, icmp->icmp_code, ntohs(icmp->icmp_cksum)); |
|
strlcat(szShow, szLine, USHRT_MAX); |
|
break; |
|
} |
|
|
|
printf("%s===\n", szShow); |
|
pthread_exit(NULL); |
|
} |
|
|
|
// ---------------------- |
|
|
|
int |
|
main(int argc, char **argv) |
|
{ |
|
u_int n, count = (u_int) -1; |
|
register int i; |
|
int dev, fd, ret, siz = 0; |
|
char szStr[BUFSIZ], szMap[MAXPATHLEN] = { 0 }, *buffer = NULL; |
|
struct ifreq ifr; |
|
struct pollfd pfd = { 0 }; |
|
pthread_t tid; |
|
char ch, mode = 'R'; |
|
struct timespec ts_start, ts_end; |
|
#ifdef __FreeBSD__ |
|
struct bpf_zbuf *bz; |
|
#endif |
|
|
|
while ((ch = getopt(argc, argv, "hvwzs:p:f:")) != -1) |
|
switch (ch) { |
|
case 'w': |
|
mode = 'W'; |
|
break; |
|
case 's': |
|
siz = strtol(optarg, NULL, 0); |
|
break; |
|
case 'p': |
|
count = strtol(optarg, NULL, 0); |
|
break; |
|
case 'f': |
|
strlcpy(szMap, optarg, sizeof szMap); |
|
break; |
|
case 'z': |
|
flg++; |
|
break; |
|
case 'v': |
|
Verbose++; |
|
break; |
|
case 'h': |
|
default: |
|
return 1; |
|
} |
|
argc -= optind; |
|
argv += optind; |
|
if (argc < 1) |
|
return 1; |
|
|
|
if (**argv == '/') |
|
strlcpy(szStr, strrchr(*argv, '/') + 1, sizeof szStr); |
|
else |
|
strlcpy(szStr, *argv, sizeof szStr); |
|
|
|
#ifdef __FreeBSD_ |
|
dev = io_etherOpen(szStr, O_RDWR | O_NONBLOCK, 42, &siz, &bz); |
|
#else |
|
dev = io_etherOpen(szStr, O_RDWR | O_NONBLOCK, 42, &siz, NULL); |
|
#endif |
|
if (dev == -1) { |
|
printf("Error:: #%d - %s\n", io_GetErrno(), io_GetError()); |
|
return 1; |
|
} else |
|
printf("dev=%d(%s)\n", dev, szStr); |
|
|
|
if (ioctl(dev, BIOCGBLEN, &n) == -1) { |
|
perror("ioctl(BIOCGBLEN)"); |
|
close(dev); |
|
return 1; |
|
} else |
|
printf("BPF buffer len=%d\n", n); |
|
|
|
#if 0 |
|
#ifdef __FreeBSD__ |
|
ret = BPF_BUFMODE_ZBUF; |
|
if (flg && !ioctl(dev, BIOCSETBUFMODE, (u_int*) &ret)) { |
|
if (ioctl(dev, BIOCGETZMAX, &ret) == -1) { |
|
perror("ioctl(BIOCGETZMAX)"); |
|
close(dev); |
|
return 1; |
|
} |
|
memset(&bz, 0, sizeof bz); |
|
bz.bz_buflen = roundup(MIN(n, ret), getpagesize()); |
|
bz.bz_bufa = mmap(NULL, bz.bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); |
|
bz.bz_bufb = mmap(NULL, bz.bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); |
|
if (bz.bz_bufa == MAP_FAILED || bz.bz_bufb == MAP_FAILED) { |
|
perror("mmap()"); |
|
close(dev); |
|
return 1; |
|
} |
|
|
|
if (ioctl(dev, BIOCSETZBUF, &bz) == -1) { |
|
perror("ioctl(BIOCSETZBUF)"); |
|
munmap(bz.bz_bufa, bz.bz_buflen); |
|
munmap(bz.bz_bufb, bz.bz_buflen); |
|
close(dev); |
|
return 1; |
|
} else |
|
siz = bz.bz_buflen; |
|
} else { |
|
#endif |
|
flg = 0; |
|
if (siz) { |
|
if (ioctl(dev, BIOCSBLEN, &siz) == -1) { |
|
perror("ioctl(BIOCSBLEN)"); |
|
close(dev); |
|
return 1; |
|
} |
|
} else |
|
siz = n; |
|
#ifdef __FreeBSD__ |
|
} |
|
#endif |
|
printf("Set buffer len to %d\n", siz); |
|
|
|
if (!flg) { |
|
if (*szMap) { |
|
fd = open(szMap, O_RDWR); |
|
if (fd == -1) { |
|
perror("open(map)"); |
|
close(dev); |
|
return 1; |
|
} |
|
buffer = mmap(NULL, siz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); |
|
close(fd); |
|
} else |
|
buffer = mmap(NULL, siz, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); |
|
if (buffer == MAP_FAILED) { |
|
perror("mmap()"); |
|
close(dev); |
|
return 1; |
|
} |
|
} |
|
|
|
memset(&ifr, 0, sizeof ifr); |
|
strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name); |
|
if (ioctl(dev, BIOCSETIF, (char*) &ifr) == -1) { |
|
perror("ioctl(BIOCSETIF)"); |
|
close(dev); |
|
#ifdef __FreeBSD__ |
|
if (flg) { |
|
munmap(bz.bz_bufa, bz.bz_buflen); |
|
munmap(bz.bz_bufb, bz.bz_buflen); |
|
} else |
|
#endif |
|
munmap(buffer, siz); |
|
return 1; |
|
} |
|
n = 1; |
|
if (ioctl(dev, BIOCSHDRCMPLT, &n) == -1) { |
|
perror("ioctl(BIOCSHDRCMPLT)"); |
|
close(dev); |
|
#ifdef __FreeBSD__ |
|
if (flg) { |
|
munmap(bz.bz_bufa, bz.bz_buflen); |
|
munmap(bz.bz_bufb, bz.bz_buflen); |
|
} else |
|
#endif |
|
munmap(buffer, siz); |
|
return 1; |
|
} |
|
if (ioctl(dev, BIOCIMMEDIATE, &n) == -1) { |
|
perror("ioctl(BIOCIMMEDIATE)"); |
|
close(dev); |
|
#ifdef __FreeBSD__ |
|
if (flg) { |
|
munmap(bz.bz_bufa, bz.bz_buflen); |
|
munmap(bz.bz_bufb, bz.bz_buflen); |
|
} else |
|
#endif |
|
munmap(buffer, siz); |
|
return 1; |
|
} |
|
|
|
pfd.fd = dev; |
|
assert(!clock_gettime(CLOCK_REALTIME, &ts_start)); |
|
if (mode == 'R') { |
|
pfd.events = POLLIN; |
|
for (i = 0; i < count; i++) { |
|
if (poll(&pfd, 1, -1) == -1) |
|
break; |
|
|
|
#ifdef __FreeBSD__ |
|
if (flg) { |
|
if (!NEXT_zbuf((void**) &buffer, &bz, &ret)) |
|
continue; |
|
if (Verbose) { |
|
printf("+readed %d bytes\n", ret); |
|
pthread_create(&tid, NULL, ShowPkt, buffer); |
|
} |
|
} else { |
|
#endif |
|
ret = read(dev, buffer, siz); |
|
if (ret == -1) |
|
printf("%d) read(%d) #%d - %s\n", i, ret, errno, strerror(errno)); |
|
if (Verbose) { |
|
printf("%d) +readed %d bytes\n", i, ret); |
|
pthread_create(&tid, NULL, ShowPkt, buffer); |
|
} |
|
#ifdef __FreeBSD__ |
|
} |
|
#endif |
|
} |
|
} else { |
|
pfd.events = POLLOUT; |
|
for (i = 0; i < count; i++) { |
|
#ifdef __FreeBSD__ |
|
if (poll(&pfd, 1, -1) == -1) |
|
break; |
|
#endif |
|
|
|
ret = write(dev, buffer, siz); |
|
if (ret == -1) |
|
printf("write(%d) #%d - %s\n", ret, errno, strerror(errno)); |
|
if (Verbose) |
|
printf("+writed %d bytes\n", ret); |
|
} |
|
} |
|
assert(!clock_gettime(CLOCK_REALTIME, &ts_end)); |
|
#endif |
|
// munmap(buffer, siz); |
|
|
|
io_etherClose(dev, &bz); |
|
|
|
time_spec_sub(&ts_end, &ts_start); |
|
printf("%d.%09lu for %d iterations\n", ts_end.tv_sec, ts_end.tv_nsec, i); |
|
ts_end.tv_sec *= 1000000000 / i; |
|
printf("0.%09lu per/iteration\n", ts_end.tv_sec + ts_end.tv_nsec / i); |
|
return 0; |
|
} |