📄 hcidump.c
字号:
return -1; } opt = 1; if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { perror("Can't enable data direction info"); return -1; } opt = 1; if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { perror("Can't enable time stamp"); return -1; } /* Setup filter */ hci_filter_clear(&flt); hci_filter_all_ptypes(&flt); hci_filter_all_events(&flt); if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { perror("Can't set filter"); return -1; } /* Bind socket to the HCI device */ addr.hci_family = AF_BLUETOOTH; addr.hci_dev = dev; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { printf("Can't attach to device hci%d. %s(%d)\n", dev, strerror(errno), errno); return -1; } return sk;}static int open_connection(char *addr, char *port){ 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; perror("Can't create socket"); freeaddrinfo(res0); exit(1); } setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); memcpy(&ss, res->ai_addr, res->ai_addrlen); 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; } 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 create_datagram(unsigned short port){ struct sockaddr_in addr; int sk, opt = 1; sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sk < 0) return -1; if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { close(sk); return -1; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(sk); return -1; } return sk;}static unsigned char ping_data[] = { 'p', 'i', 'n', 'g' };static unsigned char pong_data[] = { 'p', 'o', 'n', 'g' };static void handle_datagram(int sk){ struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); unsigned char buf[64]; ssize_t len; len = recvfrom(sk, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &addr, &addr_len); if (len != sizeof(ping_data)) return; if (memcmp(buf, ping_data, sizeof(ping_data)) != 0) return; len = sendto(sk, pong_data, sizeof(pong_data), 0, (struct sockaddr *) &addr, sizeof(addr));}static int wait_connection(char *addr, char *port){ char hname[100], hport[10]; struct addrinfo *ai, *runp; struct addrinfo hints; struct pollfd fds[3]; int err, opt, datagram, nfds = 0; memset(&hints, 0, sizeof (hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; err = getaddrinfo(dump_addr, dump_port, &hints, &ai); if (err < 0) { printf("Can't get address info: %s\n", gai_strerror(err)); return -1; } runp = ai; datagram = create_datagram(atoi(dump_port)); if (datagram < 0) { printf("server: no discover protocol\n"); } else { fds[nfds].fd = datagram; fds[nfds].events = POLLIN; nfds++; } while (runp != NULL && nfds < sizeof(fds) / sizeof(fds[0])) { fds[nfds].fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (fds[nfds].fd < 0) { perror("Can't create socket"); return -1; } fds[nfds].events = POLLIN; opt = 1; setsockopt(fds[nfds].fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); opt = 0; setsockopt(fds[nfds].fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt)); if (bind(fds[nfds].fd, runp->ai_addr, runp->ai_addrlen) < 0) { if (errno != EADDRINUSE) { perror("Can't bind socket"); return -1; } close(fds[nfds].fd); } else { if (listen(fds[nfds].fd, SOMAXCONN) < 0) { perror("Can't listen on socket"); return -1; } getnameinfo(runp->ai_addr, runp->ai_addrlen, hname, sizeof(hname), hport, sizeof(hport), NI_NUMERICSERV); printf("server: %s:%s snap_len: %d filter: 0x%lx\n", hname, hport, snap_len, parser.filter); nfds++; } runp = runp->ai_next; } freeaddrinfo(ai); while (1) { int i, n = poll(fds, nfds, -1); if (n <= 0) continue; for (i = 0; i < nfds; i++) { struct sockaddr_storage rem; socklen_t remlen = sizeof(rem); int sk; if (!(fds[i].revents & POLLIN)) continue; if (fds[i].fd == datagram) { handle_datagram(datagram); continue; } sk = accept(fds[i].fd, (struct sockaddr *) &rem, &remlen); if (sk < 0) continue; getnameinfo((struct sockaddr *) &rem, remlen, hname, sizeof(hname), hport, sizeof(hport), NI_NUMERICSERV); printf("client: %s:%s snap_len: %d filter: 0x%lx\n", hname, hport, snap_len, parser.filter); for (n = 0; n < nfds; n++) close(fds[n].fd); return sk; } } return -1;}static int run_server(int dev, char *addr, char *port, unsigned long flags){ while (1) { int dd, sk; sk = wait_connection(addr, port); if (sk < 0) continue; //fcntl(sk, F_SETFL, O_NONBLOCK); dd = open_socket(dev, flags); if (dd < 0) { close(sk); continue; } process_frames(dev, dd, sk, flags); close(dd); close(sk); } return 0;}static struct { char *name; int flag;} filters[] = { { "lmp", FILT_LMP }, { "hci", FILT_HCI }, { "sco", FILT_SCO }, { "l2cap", FILT_L2CAP }, { "rfcomm", FILT_RFCOMM }, { "sdp", FILT_SDP }, { "bnep", FILT_BNEP }, { "cmtp", FILT_CMTP }, { "hidp", FILT_HIDP }, { "hcrp", FILT_HCRP }, { "avdtp", FILT_AVDTP }, { "avctp", FILT_AVCTP }, { "obex", FILT_OBEX }, { "capi", FILT_CAPI }, { "ppp", FILT_PPP }, { "csr", FILT_CSR }, { "dga", FILT_DGA }, { 0 }};static unsigned long parse_filter(int argc, char **argv){ unsigned long filter = 0; int i,n; for (i = 0; i < argc; i++) { for (n = 0; filters[n].name; n++) { if (!strcasecmp(filters[n].name, argv[i])) { filter |= filters[n].flag; break; } } } return filter;}static void usage(void){ printf( "Usage: hcidump [OPTION...] [filter]\n" " -i, --device=hci_dev HCI device\n" " -l, --snap-len=len Snap len (in bytes)\n" " -p, --psm=psm Default PSM\n" " -m, --manufacturer=compid Default manufacturer\n" " -w, --save-dump=file Save dump to a file\n" " -r, --read-dump=file Read dump from a file\n" " -s, --send-dump=host Send dump to a host\n" " -n, --recv-dump=host Receive dump on a host\n" " -d, --wait-dump=host Wait on a host and send\n" " -t, --ts Display time stamps\n" " -a, --ascii Dump data in ascii\n" " -x, --hex Dump data in hex\n" " -X, --ext Dump data in hex and ascii\n" " -R, --raw Dump raw data\n" " -C, --cmtp=psm PSM for CMTP\n" " -H, --hcrp=psm PSM for HCRP\n" " -O, --obex=channel Channel for OBEX\n" " -P, --ppp=channel Channel for PPP\n" " -D, --pppdump=file Extract PPP traffic\n" " -A, --audio=file Extract SCO audio data\n" " -B, --btsnoop Use BTSnoop file format\n" " -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" );}static struct option main_options[] = { { "device", 1, 0, 'i' }, { "snap-len", 1, 0, 'l' }, { "psm", 1, 0, 'p' }, { "manufacturer", 1, 0, 'm' }, { "save-dump", 1, 0, 'w' }, { "read-dump", 1, 0, 'r' }, { "send-dump", 1, 0, 's' }, { "recv-dump", 1, 0, 'n' }, { "wait-dump", 1, 0, 'd' }, { "timestamp", 0, 0, 't' }, { "ascii", 0, 0, 'a' }, { "hex", 0, 0, 'x' }, { "ext", 0, 0, 'X' }, { "raw", 0, 0, 'R' }, { "cmtp", 1, 0, 'C' }, { "hcrp", 1, 0, 'H' }, { "obex", 1, 0, 'O' }, { "ppp", 1, 0, 'P' }, { "pppdump", 1, 0, 'D' }, { "audio", 1, 0, 'A' }, { "btsnoop", 0, 0, 'B' }, { "verbose", 0, 0, 'V' }, { "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[]){ unsigned long flags = 0; unsigned long filter = 0; int device = 0; int defpsm = 0; int defcompid = DEFAULT_COMPID; 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:d:taxXRC:H:O:P:D:A:BVYZN46h", main_options, NULL)) != -1) { switch(opt) { case 'i': if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system")) device = atoi(optarg + 3); else device = HCI_DEV_NONE; break; case 'l': snap_len = atoi(optarg); break; case 'p': defpsm = atoi(optarg); break; case 'm': defcompid = atoi(optarg); break; case 'w': mode = WRITE; dump_file = strdup(optarg); break; case 'r': mode = READ; dump_file = strdup(optarg); break; case 's': mode = SEND; dump_addr = optarg; break; case 'n': mode = RECEIVE; dump_addr = optarg; break; case 'd': mode = SERVER; dump_addr = optarg; break; case 't': flags |= DUMP_TSTAMP; break; case 'a': flags |= DUMP_ASCII; break; case 'x': flags |= DUMP_HEX; break; case 'X': flags |= DUMP_EXT; break; case 'R': flags |= DUMP_RAW; break; case 'C': set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP); break; case 'H': set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL); break; case 'O': set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX); break; case 'P': set_proto(0, 0, atoi(optarg), SDP_UUID_LAN_ACCESS_PPP); break; case 'D': pppdump_file = strdup(optarg); break; case 'A': audio_file = strdup(optarg); break; case 'B': flags |= DUMP_BTSNOOP; break; case 'V': flags |= DUMP_VERBOSE; break; case 'Y': flags |= DUMP_NOVENDOR; break; case 'Z': permcheck = 0; break; case 'N': noappend = 1; break; case '4': af = AF_INET; break; case '6': af = AF_INET6; break; case 'h': default: usage(); exit(0); } } argc -= optind; argv += optind; optind = 0; if (argc > 0) filter = parse_filter(argc, argv); /* Default settings */ if (!filter) filter = ~0L; if (pppdump_file) pppdump_fd = open_file(pppdump_file, PPPDUMP, flags); if (audio_file) audio_fd = open_file(audio_file, AUDIO, flags); switch (mode) { case PARSE: init_parser(flags, filter, defpsm, defcompid, pppdump_fd, audio_fd); process_frames(device, open_socket(device, flags), -1, flags); break; case READ: init_parser(flags, filter, defpsm, defcompid, pppdump_fd, audio_fd); read_dump(open_file(dump_file, mode, flags)); break; case WRITE: process_frames(device, open_socket(device, flags), open_file(dump_file, mode, flags), flags); break; case RECEIVE: init_parser(flags, filter, defpsm, defcompid, pppdump_fd, audio_fd); read_dump(wait_connection(dump_addr, dump_port)); break; case SEND: process_frames(device, open_socket(device, flags), open_connection(dump_addr, dump_port), flags); break; case SERVER: init_parser(flags, filter, defpsm, defcompid, pppdump_fd, audio_fd); run_server(device, dump_addr, dump_port, flags); break; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -