From 52241871a690cbb0eb71709d635665632c51835f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 4 Oct 2006 13:53:33 +0000 Subject: [PATCH] hcidump: Add IPv6 support --- tools/hcidump.1 | 6 ++ tools/hcidump.c | 217 +++++++++++++++++++++++++++---------------- tools/parser/bnep.c | 54 ++++++++--- tools/parser/tcpip.c | 66 ++++++++++--- 4 files changed, 235 insertions(+), 108 deletions(-) diff --git a/tools/hcidump.1 b/tools/hcidump.1 index 913471c77..f0aa4d4e6 100644 --- a/tools/hcidump.1 +++ b/tools/hcidump.1 @@ -108,6 +108,12 @@ Don't display any vendor commands or events and don't show any pin code or link .TP .BR -N ", " "\-\^\-noappend" No appending to existing files. Always create new files. +.TP +.BR -4 ", " "\-\^\-ipv4" +Use IPv4 when sending information over the network +.TP +.BR -6 ", " "\-\^\-ipv6" +Use IPv6 when sending information over the network .SH FILTERS .B filter diff --git a/tools/hcidump.c b/tools/hcidump.c index f1d082532..0458ab4cf 100644 --- a/tools/hcidump.c +++ b/tools/hcidump.c @@ -66,7 +66,7 @@ static inline uint64_t ntoh64(uint64_t n) #define hton64(x) ntoh64(x) #define SNAP_LEN HCI_MAX_FRAME_SIZE -#define DEFAULT_PORT 10839; +#define DEFAULT_PORT "10839"; /* Modes */ enum { @@ -92,8 +92,9 @@ static long filter; static char *dump_file = NULL; static char *pppdump_file = NULL; static char *audio_file = NULL; -static in_addr_t dump_addr = INADDR_LOOPBACK; -static in_port_t dump_port = DEFAULT_PORT; +static char *dump_addr; +static char *dump_port = DEFAULT_PORT; +static int af = AF_UNSPEC; struct hcidump_hdr { uint16_t len; @@ -504,88 +505,146 @@ static int open_socket(int dev, unsigned long flags) return sk; } -static int open_connection(in_addr_t addr, in_port_t port) +static int open_connection(char *addr, char *port) { - struct sockaddr_in sa; - int sk, opt; + struct sockaddr_storage ss; + struct addrinfo hints, *res0, *res; + int sk = -1, opt = 1; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(addr, port, &hints, &res0)) + if(getaddrinfo(NULL, port, &hints, &res0)) { + perror("getaddrinfo"); + exit(1); + } + + for (res = res0; res; res = res->ai_next) { + sk = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sk < 0) { + if (res->ai_next) + continue; - sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sk < 0) { - perror("Can't create inet socket"); - exit(1); - } + perror("Can't create socket"); + freeaddrinfo(res0); + exit(1); + } - opt = 1; - setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + memcpy(&ss, res->ai_addr, res->ai_addrlen); - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(INADDR_ANY); - sa.sin_port = htons(0); - if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - perror("Can't bind inet socket"); - close(sk); - exit(1); - } + switch(ss.ss_family) { + case AF_INET: + ((struct sockaddr_in *) &ss)->sin_addr.s_addr = htonl(INADDR_ANY); + ((struct sockaddr_in *) &ss)->sin_port = 0; + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6 *) &ss)->sin6_addr, &in6addr_any, sizeof(in6addr_any)); + ((struct sockaddr_in6 *) &ss)->sin6_port = 0; + break; + } - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(addr); - sa.sin_port = htons(port); - if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - perror("Can't connect inet socket"); - close(sk); - exit(1); + if (bind(sk, (struct sockaddr *) &ss, sizeof(ss)) < 0) { + perror("Can't bind socket"); + close(sk); + freeaddrinfo(res0); + exit(1); + } + + if (connect(sk, res->ai_addr, res->ai_addrlen) < 0) { + perror("Can't connect socket"); + close(sk); + freeaddrinfo(res0); + exit(1); + } } + freeaddrinfo(res0); + return sk; } -static int wait_connection(in_addr_t addr, in_port_t port) +static int wait_connection(char *addr, char *port) { - struct sockaddr_in sa; - struct hostent *host; + char hname[100], hport[10]; + struct sockaddr_storage ss; + struct addrinfo hints, *res0, *res; socklen_t len; - int sk, nsk, opt; + int sk = -1, nsk, opt = 1; - sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sk < 0) { - perror("Can't create inet socket"); - exit(1); - } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - opt = 1; - setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (getaddrinfo(addr, port, &hints, &res0)) + if (getaddrinfo(NULL, port, &hints, &res0)) { + perror("getaddrinfo"); + exit(1); + } + + for (res = res0; res; res = res->ai_next) { + sk = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sk < 0) { + if (res->ai_next) + continue; - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(addr); - sa.sin_port = htons(port); - if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - perror("Can't bind inet socket"); - close(sk); - exit(1); - } + perror("Can't create socket"); + freeaddrinfo(res0); + exit(1); + } - host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET); - printf("device: %s:%d snap_len: %d filter: 0x%lx\n", - host ? host->h_name : inet_ntoa(sa.sin_addr), - ntohs(sa.sin_port), snap_len, filter); + setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - if (listen(sk, 1)) { - perror("Can't listen on inet socket"); - close(sk); - exit(1); + if (bind(sk, res->ai_addr, res->ai_addrlen) < 0) { + if(res->ai_next) { + close(sk); + continue; + } + + perror("Can't bind socket"); + close(sk); + freeaddrinfo(res0); + exit(1); + } + + getnameinfo(res->ai_addr, res->ai_addrlen, hname, sizeof(hname), + hport, sizeof(hport), NI_NUMERICSERV); + printf("device: %s:%s snap_len: %d filter: 0x%lx\n", + hname, hport, snap_len, filter); + if (listen(sk, 1) < 0) { + if (res->ai_next) { + close(sk); + continue; + } + + perror("Can't listen on socket"); + close(sk); + freeaddrinfo(res0); + exit(1); + } } - len = sizeof(sa); - nsk = accept(sk, (struct sockaddr *) &sa, &len); + freeaddrinfo(res0); + + len = sizeof(ss); + nsk = accept(sk, (struct sockaddr *) &ss, &len); if (nsk < 0) { - perror("Can't accept new inet socket"); + perror("Can't accept new socket"); close(sk); + freeaddrinfo(res0); exit(1); } - host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET); - printf("device: %s snap_len: %d filter: 0x%lx\n", - host ? host->h_name : inet_ntoa(sa.sin_addr), snap_len, filter); + getnameinfo((struct sockaddr *) &ss, sizeof(ss), + hname, sizeof(hname), NULL, 0, 0); + + printf("device: %s snap_len: %d filter: 0x%lx\n", + hname, snap_len, filter); close(sk); @@ -657,6 +716,8 @@ static void usage(void) " -V, --verbose Verbose decoding\n" " -Y, --novendor No vendor commands or events\n" " -N, --noappend No appending to existing files\n" + " -4, --ipv4 Use IPv4 as transport\n" + " -6 --ipv6 Use IPv6 as transport\n" " -h, --help Give this help list\n" " --usage Give a short usage message\n" ); @@ -687,19 +748,19 @@ static struct option main_options[] = { { "novendor", 0, 0, 'Y' }, { "nopermcheck", 0, 0, 'Z' }, { "noappend", 0, 0, 'N' }, + { "ipv4", 0, 0, '4' }, + { "ipv6", 0, 0, '6' }, { "help", 0, 0, 'h' }, { 0 } }; int main(int argc, char *argv[]) { - struct hostent *host; - struct in_addr addr; int opt, pppdump_fd = -1, audio_fd = -1; printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION); - while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:P:D:A:BVYZNh", main_options, NULL)) != -1) { + while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:P:D:A:BVYZN46h", main_options, NULL)) != -1) { switch(opt) { case 'i': if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system")) @@ -732,28 +793,12 @@ int main(int argc, char *argv[]) case 's': mode = SEND; - host = gethostbyname(optarg); - if (host) { - bcopy(host->h_addr, &addr, sizeof(struct in_addr)); - dump_addr = ntohl(addr.s_addr); - dump_port = DEFAULT_PORT; - } else { - dump_addr = INADDR_LOOPBACK; - dump_port = DEFAULT_PORT; - } + dump_addr = optarg; break; case 'n': mode = RECEIVE; - host = gethostbyname(optarg); - if (host) { - bcopy(host->h_addr, &addr, sizeof(struct in_addr)); - dump_addr = ntohl(addr.s_addr); - dump_port = DEFAULT_PORT; - } else { - dump_addr = INADDR_LOOPBACK; - dump_port = DEFAULT_PORT; - } + dump_addr = optarg; break; case 't': @@ -820,6 +865,14 @@ int main(int argc, char *argv[]) noappend = 1; break; + case '4': + af = AF_INET; + break; + + case '6': + af = AF_INET6; + break; + case 'h': default: usage(); diff --git a/tools/parser/bnep.c b/tools/parser/bnep.c index 05aad2a86..d026162fd 100644 --- a/tools/parser/bnep.c +++ b/tools/parser/bnep.c @@ -56,6 +56,10 @@ /* BNEP Extension Type */ #define BNEP_EXTENSION_CONTROL 0x00 +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 ETH_P_IPV6 +#endif + static char *get_macaddr(struct frame *frm) { static char str[20]; @@ -63,8 +67,10 @@ static char *get_macaddr(struct frame *frm) sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + frm->ptr += 6; frm->len -= 6; + return str; } @@ -131,12 +137,14 @@ static void bnep_control(int level, struct frame *frm, int header_length) break; case BNEP_SETUP_CONNECTION_RESPONSE_MSG: - printf("Setup Rsp(0x%02x) res 0x%04x\n", type, get_u16(frm)); + printf("Setup Rsp(0x%02x) res 0x%04x\n", + type, get_u16(frm)); break; case BNEP_FILTER_NET_TYPE_SET_MSG: length = get_u16(frm); - printf("Filter NetType Set(0x%02x) len 0x%04x\n", type, length); + printf("Filter NetType Set(0x%02x) len 0x%04x\n", + type, length); for (i = 0; i < length / 4; i++) { p_indent(level + 1, frm); printf("0x%04x - ", get_u16(frm)); @@ -145,12 +153,14 @@ static void bnep_control(int level, struct frame *frm, int header_length) break; case BNEP_FILTER_NET_TYPE_RESPONSE_MSG: - printf("Filter NetType Rsp(0x%02x) res 0x%04x\n", type, get_u16(frm)); + printf("Filter NetType Rsp(0x%02x) res 0x%04x\n", + type, get_u16(frm)); break; case BNEP_FILTER_MULT_ADDR_SET_MSG: length = get_u16(frm); - printf("Filter MultAddr Set(0x%02x) len 0x%04x\n", type, length); + printf("Filter MultAddr Set(0x%02x) len 0x%04x\n", + type, length); for (i = 0; i < length / 12; i++) { p_indent(level + 1, frm); printf("%s - ", get_macaddr(frm)); @@ -159,7 +169,8 @@ static void bnep_control(int level, struct frame *frm, int header_length) break; case BNEP_FILTER_MULT_ADDR_RESPONSE_MSG: - printf("Filter MultAddr Rsp(0x%02x) res 0x%04x\n", type, get_u16(frm)); + printf("Filter MultAddr Rsp(0x%02x) res 0x%04x\n", + type, get_u16(frm)); break; default: @@ -174,26 +185,28 @@ static void bnep_control(int level, struct frame *frm, int header_length) static void bnep_eval_extension(int level, struct frame *frm) { uint8_t type = get_u8(frm); - int extension = type & 0x80; uint8_t length = get_u8(frm); + int extension = type & 0x80; p_indent(level, frm); + switch (type & 0x7f) { case BNEP_EXTENSION_CONTROL: - printf("Ext Control(0x%02x|%s) len 0x%02x\n", type & 0x7f, extension ? "1" : "0", length); + printf("Ext Control(0x%02x|%s) len 0x%02x\n", + type & 0x7f, extension ? "1" : "0", length); bnep_control(level, frm, length); break; default: - printf("Ext Unknown(0x%02x|%s) len 0x%02x\n", type & 0x7f, extension ? "1" : "0", length); + printf("Ext Unknown(0x%02x|%s) len 0x%02x\n", + type & 0x7f, extension ? "1" : "0", length); raw_ndump(level + 1, frm, length); frm->ptr += length; frm->len -= length; } - if (extension) { + if (extension) bnep_eval_extension(level, frm); - } } void bnep_dump(int level, struct frame *frm) @@ -206,19 +219,22 @@ void bnep_dump(int level, struct frame *frm) switch (type & 0x7f) { case BNEP_CONTROL: - printf("BNEP: Control(0x%02x|%s)\n", type & 0x7f, extension ? "1" : "0"); + printf("BNEP: Control(0x%02x|%s)\n", + type & 0x7f, extension ? "1" : "0"); bnep_control(level, frm, -1); break; case BNEP_COMPRESSED_ETHERNET: - printf("BNEP: Compressed(0x%02x|%s)\n", type & 0x7f, extension ? "1" : "0"); + printf("BNEP: Compressed(0x%02x|%s)\n", + type & 0x7f, extension ? "1" : "0"); p_indent(++level, frm); proto = get_u16(frm); printf("[proto 0x%04x]\n", proto); break; case BNEP_GENERAL_ETHERNET: - printf("BNEP: General ethernet(0x%02x|%s)\n", type & 0x7f, extension ? "1" : "0"); + printf("BNEP: General ethernet(0x%02x|%s)\n", + type & 0x7f, extension ? "1" : "0"); p_indent(++level, frm); printf("dst %s ", get_macaddr(frm)); printf("src %s ", get_macaddr(frm)); @@ -227,7 +243,8 @@ void bnep_dump(int level, struct frame *frm) break; case BNEP_COMPRESSED_ETHERNET_DEST_ONLY: - printf("BNEP: Compressed DestOnly(0x%02x|%s)\n", type & 0x7f, extension ? "1" : "0"); + printf("BNEP: Compressed DestOnly(0x%02x|%s)\n", + type & 0x7f, extension ? "1" : "0"); p_indent(++level, frm); printf("dst %s ", get_macaddr(frm)); proto = get_u16(frm); @@ -235,7 +252,8 @@ void bnep_dump(int level, struct frame *frm) break; case BNEP_COMPRESSED_ETHERNET_SOURCE_ONLY: - printf("BNEP: Compressed SrcOnly(0x%02x|%s)\n", type & 0x7f, extension ? "1" : "0"); + printf("BNEP: Compressed SrcOnly(0x%02x|%s)\n", + type & 0x7f, extension ? "1" : "0"); p_indent(++level, frm); printf("src %s ", get_macaddr(frm)); proto = get_u16(frm); @@ -287,6 +305,12 @@ void bnep_dump(int level, struct frame *frm) ip_dump(level, frm); break; + case ETHERTYPE_IPV6: + p_indent(++level, frm); + printf("IPV6: "); + ip_dump(level, frm); + break; + default: raw_dump(level, frm); break; diff --git a/tools/parser/tcpip.c b/tools/parser/tcpip.c index d8791a7eb..6afac2b4b 100644 --- a/tools/parser/tcpip.c +++ b/tools/parser/tcpip.c @@ -35,26 +35,37 @@ #include #include #include +#include #include #include +#include #include "parser.h" void arp_dump(int level, struct frame *frm) { int i; + char buf[20]; + struct sockaddr_in sai; struct ether_arp *arp = (struct ether_arp *) frm->ptr; printf("Src "); for (i = 0; i < 5; i++) printf("%02x:", arp->arp_sha[i]); printf("%02x", arp->arp_sha[5]); - printf("(%s) ", inet_ntoa(*(struct in_addr *) &arp->arp_spa)); + sai.sin_family = AF_INET; + memcpy(&sai.sin_addr, &arp->arp_spa, sizeof(sai.sin_addr)); + getnameinfo((struct sockaddr *) &sai, sizeof(sai), buf, sizeof(buf), + NULL, 0, NI_NUMERICHOST); + printf("(%s) ", buf); printf("Tgt "); for (i = 0; i < 5; i++) printf("%02x:", arp->arp_tha[i]); printf("%02x", arp->arp_tha[5]); - printf("(%s)\n", inet_ntoa(*(struct in_addr *) &arp->arp_tpa)); + memcpy(&sai.sin_addr, &arp->arp_tpa, sizeof(sai.sin_addr)); + getnameinfo((struct sockaddr *) &sai, sizeof(sai), buf, sizeof(buf), + NULL, 0, NI_NUMERICHOST); + printf("(%s)\n", buf); frm->ptr += sizeof(struct ether_arp); frm->len -= sizeof(struct ether_arp); raw_dump(level, frm); // not needed. @@ -62,33 +73,66 @@ void arp_dump(int level, struct frame *frm) void ip_dump(int level, struct frame *frm) { + char src[50], dst[50]; struct ip *ip = (struct ip *) (frm->ptr); - int len = ip->ip_hl << 2; + int len; + uint8_t proto = 0; + + if (ip->ip_v == 4) { + struct sockaddr_in sai; + proto = ip->ip_p; + len = ip->ip_hl << 2; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_INET; + memcpy(&sai.sin_addr, &ip->ip_src, sizeof(struct in_addr)); + getnameinfo((struct sockaddr *) &sai, sizeof(sai), + src, sizeof(src), NULL, 0, NI_NUMERICHOST); + memcpy(&sai.sin_addr, &ip->ip_dst, sizeof(struct in_addr)); + getnameinfo((struct sockaddr *) &sai, sizeof(sai), + dst, sizeof(dst), NULL, 0, NI_NUMERICHOST); + } else if (ip->ip_v == 6) { + struct sockaddr_in6 sai6; + struct ip6_hdr *ip6 = (struct ip6_hdr *) ip; + proto = ip6->ip6_nxt; + len = sizeof(struct ip6_hdr); + memset(&sai6, 0, sizeof(sai6)); + sai6.sin6_family = AF_INET6; + memcpy(&sai6.sin6_addr, &ip6->ip6_src, sizeof(struct in6_addr)); + getnameinfo((struct sockaddr *) &sai6, sizeof(sai6), + src, sizeof(src), NULL, 0, NI_NUMERICHOST); + memcpy(&sai6.sin6_addr, &ip6->ip6_dst, sizeof(struct in6_addr)); + getnameinfo((struct sockaddr *) &sai6, sizeof(sai6), + dst, sizeof(dst), NULL, 0, NI_NUMERICHOST); + } + + printf("src %s ", src); + printf("dst %s\n", dst); + frm->ptr += len; frm->len -= len; - - printf("src %s ", inet_ntoa(*(struct in_addr *) &(ip->ip_src))); - printf("dst %s\n", inet_ntoa(*(struct in_addr *) &(ip->ip_dst))); p_indent(++level, frm); - switch (ip->ip_p) { + switch (proto) { case IPPROTO_TCP: printf("TCP:\n"); - raw_dump(level, frm); break; case IPPROTO_UDP: printf("UDP:\n"); - raw_dump(level, frm); break; case IPPROTO_ICMP: printf("ICMP:\n"); - raw_dump(level, frm); + break; + + case IPPROTO_ICMPV6: + printf("ICMPv6:\n"); break; default: printf("Unknown Protocol: 0x%02x\n", ip->ip_p); - raw_dump(level, frm); + break; } + + raw_dump(level, frm); } -- 2.47.3