diff --git a/tools/hcidump.1 b/tools/hcidump.1
index 913471c..f0aa4d4 100644
--- a/tools/hcidump.1
+++ b/tools/hcidump.1
.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 f1d0825..0458ab4 100644
--- a/tools/hcidump.c
+++ b/tools/hcidump.c
#define hton64(x) ntoh64(x)
#define SNAP_LEN HCI_MAX_FRAME_SIZE
-#define DEFAULT_PORT 10839;
+#define DEFAULT_PORT "10839";
/* Modes */
enum {
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;
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);
" -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"
);
{ "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"))
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':
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 05aad2a..d026162 100644
--- a/tools/parser/bnep.c
+++ b/tools/parser/bnep.c
/* 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];
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;
}
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));
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));
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:
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)
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));
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);
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);
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 d8791a7..6afac2b 100644
--- a/tools/parser/tcpip.c
+++ b/tools/parser/tcpip.c
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <netinet/ip6.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
+#include <netdb.h>
#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.
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);
}