diff options
author | Luca Deri <deri@Lucas-MacBookPro.local> | 2015-04-19 07:25:59 +0200 |
---|---|---|
committer | Luca Deri <deri@Lucas-MacBookPro.local> | 2015-04-19 07:25:59 +0200 |
commit | 2e5ceac844c32fb52f4f3042be5b872f8b0b4ff0 (patch) | |
tree | 01af171f4af2b86efa64d0166dc540ee5c027c95 /src/lib/protocols/btlib.c | |
parent | 7fa4694dadf869d1de2baa99383308a163902f8f (diff) |
Initial import from SVN
Diffstat (limited to 'src/lib/protocols/btlib.c')
-rw-r--r-- | src/lib/protocols/btlib.c | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/src/lib/protocols/btlib.c b/src/lib/protocols/btlib.c new file mode 100644 index 000000000..6442c7db7 --- /dev/null +++ b/src/lib/protocols/btlib.c @@ -0,0 +1,509 @@ +/* + * btlib.c + * + * Copyright (C) 2011-15 - ntop.org + * Contributed by Vitaly Lavrov <vel21ripn@gmail.com> + * + * This file is part of nDPI, an open source deep packet inspection + * library based on the OpenDPI and PACE technology by ipoque GmbH + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef NDPI_NO_STD_INC +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <strings.h> + +typedef unsigned char u_int8_t; +typedef unsigned short int u_int16_t; +typedef unsigned long long int u_int64_t; + +#include <stdint.h> +#include <stdlib.h> +#include <arpa/inet.h> +#endif + +typedef signed long long int i_int64_t; + +#include "btlib.h" + +#ifndef __KERNEL__ + +int bt_parse_debug = 0; + +static char *printXb(char *s,const u_int8_t *b,int l) { + int i; + for(i=0; i < l; i++) + snprintf(&s[i*2],41,"%02x",b[i]); + return s; +} + +static char *print20b(char *s,const u_int8_t *b) { + snprintf(s,41,"%08x%08x%08x%08x%08x", + htonl(*(u_int32_t*)b), + htonl(*(u_int32_t*)(b+4)), + htonl(*(u_int32_t*)(b+8)), + htonl(*(u_int32_t*)(b+12)), + htonl(*(u_int32_t*)(b+16))); + return s; +} + +static char *print_id_ip_p(char *s, const struct bt_nodes_data *b) { + u_int8_t *p = (void*)b; + print20b(s,b->id); + snprintf(s+40,39," %d.%d.%d.%d:%u", + p[20], p[21], p[22], p[23], htons(b->port)); + return s; +} + +static char *print_ip_p(char *s, const struct bt_ipv4p *b,int np) { + const u_int8_t *p = (const void*)b; + snprintf(s,39,!np ? "%d.%d.%d.%d:%u":"%d.%d.%d.%d", + p[0], p[1], p[2], p[3], htons(b->port)); + return s; +} + +static char *print_ip6_p(char *s, const struct bt_ipv6p *b,int np) { + u_int16_t *p = (void*)b; + snprintf(s,79,!np ? "%x:%x:%x:%x:%x:%x:%x:%x.%u":"%x:%x:%x:%x:%x:%x:%x:%x", + htons(p[0]), htons(p[1]), htons(p[2]), htons(p[3]), + htons(p[4]), htons(p[5]), htons(p[6]), htons(p[7]), + htons(b->port)); + return s; +} + +static char *print_id_ip6_p(char *s,const struct bt_nodes6_data *b) { + return print_ip6_p(s,(struct bt_ipv6p *)&b->ip,0); +} + + +void dump_bt_proto_struct(struct bt_parse_protocol *p) { + char b20h[128]; + int i; + + if(p->y_e && p->e_msg) { + printf("Error %s/%u\n", p->e_msg, p->e_len); + } + if(p->y_q) { + printf("Query "); + if(p->q_ping) printf("ping\n"); + if(p->q_g_peers) printf("get_peers\n"); + if(p->q_f_node) printf("find_node\n"); + if(p->q_a_peer) printf("announce_peer\n"); + } + if(p->y_r) + printf("Reply\n"); + + if(p->t) printf("\tt\t%llx\n",p->t); + if(p->v) printf("\tv\t%llx\n",p->v); + if(p->ip) printf("\tIP\t%s\n",print_ip_p(b20h,p->ip,0)); + + if(p->a.port) printf("\tport\t%d\n",htons(p->a.port)); + if(p->a.id) printf("\tID\t%s\n",print20b(b20h,p->a.id)); + if(p->a.target) printf("\ttarget\t%s\n",print20b(b20h,p->a.target)); + if(p->a.token) printf("\ttoken\t%s\n",printXb(b20h,p->a.token,p->a.t_len)); + if(p->a.info_hash) printf("\ti_hash\t%s\n",print20b(b20h,p->a.info_hash)); + if(p->a.name && p->a.name_len) printf("\tname\t%.*s\n",p->a.name_len,p->a.name); + + if(p->r.ip) printf("\tip\t%s\n",print_ip_p(b20h,p->r.ip,1)); + if(p->r.port) printf("\tport\t%d\n",htons(p->r.port)); + if(p->r.id) printf("\tID\t%s\n",print20b(b20h,p->r.id)); + if(p->r.token) printf("\ttoken\t%s\n",printXb(b20h,p->r.token,p->r.t_len)); + if(p->r.name && p->r.name_len) printf("\tname\t%.*s\n",p->r.name_len,p->r.name); + if(p->r.values && p->r.nv) { + struct bt_ipv4p2 *n = (struct bt_ipv4p2 *)p->r.values; + for(i=0;i < p->r.nv; i++,n++) { + printf("\tvalues\t%s\n", print_ip_p(b20h,&n->d,0)); + } + } + if(p->r.values6 && p->r.nv6) { + struct bt_ipv6p2 *n = (struct bt_ipv6p2 *)p->r.values6; + for(i=0;i < p->r.nv6; i++,n++) { + printf("\tvalues6\t%s\n", print_ip6_p(b20h,&n->d,0)); + } + } + if(p->r.nodes && p->r.nn) { + for(i=0;i < p->r.nn; i++) { + printf("\tnodes\t%s\n",print_id_ip_p(b20h,p->r.nodes+i)); + } + } + if(p->r.nodes6 && p->r.nn6) { + for(i=0;i < p->r.nn6; i++) { + printf("\tnodes6\t%s\n",print_id_ip6_p(b20h,p->r.nodes6+i)); + } + } + + if(p->peers && p->n_peers) { + for(i=0;i < p->n_peers; i++) { + printf("\tpeers\t%s\n",print_ip_p(b20h,p->peers+i,0)); + } + } + + if(p->interval) printf("\tinterval\t%d\n",p->interval); + if(p->min_interval) printf("\tmin interval\t%d\n",p->min_interval); +} + +static void _print_safe_str(char *msg,char *k,const u_int8_t *s,size_t l) { + static const char *th="0123456789abcdef?"; + char *buf = (char*)ndpi_malloc((size_t)(l*3+2)); + + int sl = l; + if(buf) { + char *b = buf; + for(;l > 0; s++,l--) { + if(*s < ' ' || *s >= 127) { + *b++ = '%'; + *b++ = th[(*s >> 4)&0xf]; + *b++ = th[(*s)&0xf]; + } else *b++ = *s; + } + *b = 0; + + printf("%s %s %s len %d\n",msg,k,buf ? buf:"",sl); + + ndpi_free(buf); + } +} + +static void print_safe_str(char *msg,bt_parse_data_cb_t *cbd) { + _print_safe_str(msg,cbd->buf,cbd->v.s.s,cbd->v.s.l); +} +#define DEBUG_TRACE(cmd) { if(bt_parse_debug) cmd; } +#else +#define DEBUG_TRACE(cmd,args...) +#endif /* __KERNEL */ + +#define STREQ(a,b) !strcmp(a,b) + + +void cb_data(bt_parse_data_cb_t *cbd,int *ret) { + struct bt_parse_protocol *p = &(cbd->p); + const u_int8_t *s; + const char *ss; + + if(cbd->t == 0) return; + + if(cbd->t == 1) { + + DEBUG_TRACE(printf("%s %lld\n",cbd->buf,cbd->v.i)); + + if(STREQ(cbd->buf,"a.port")) { + p->a.port = (u_int16_t)(cbd->v.i & 0xffff); + return; + } + if( + STREQ(cbd->buf,"a.implied_port") || + STREQ(cbd->buf,"a.noseed") || + STREQ(cbd->buf,"a.scrape") || + STREQ(cbd->buf,"a.seed") || + STREQ(cbd->buf,"a.vote") + ) { + return; + } + if(STREQ(cbd->buf,"r.port") || STREQ(cbd->buf,"r.p")) { + p->r.port = (u_int16_t)(cbd->v.i & 0xffff); + return; + } + if(STREQ(cbd->buf,"interval")) { + p->interval = (u_int16_t)(cbd->v.i & 0x7fffffff); + p->h_int = 1; + return; + } + if(STREQ(cbd->buf,"min interval")) { + p->min_interval = (u_int16_t)(cbd->v.i & 0x7fffffff); + p->h_mint = 1; + return; + } + DEBUG_TRACE(printf("UNKNOWN %s %lld\n",cbd->buf,cbd->v.i)); + return; + } + if(cbd->t != 2) { + DEBUG_TRACE(printf("BUG! t=%d %s\n",cbd->t,cbd->buf)); + return; + } + DEBUG_TRACE(print_safe_str("",cbd)); + + s = cbd->v.s.s; + ss = (char *)s; + + if(STREQ(cbd->buf,"a.id")) { + p->a.id = s; + return; + } + if(STREQ(cbd->buf,"a.info_hash")) { + p->a.info_hash = s; + return; + } + if(STREQ(cbd->buf,"a.target")) { + p->a.target = s; + return; + } + if(STREQ(cbd->buf,"a.token")) { + p->a.token = s; + p->a.t_len = cbd->v.s.l; + return; + } + if(STREQ(cbd->buf,"a.name")) { + p->a.name = s; + p->a.name_len = cbd->v.s.l; + return; + } + if(STREQ(cbd->buf,"a.want")) { + return; + } + + if(STREQ(cbd->buf,"r.id")) { + p->r.id = s; + return; + } + if(STREQ(cbd->buf,"r.ip")) { + if(cbd->v.s.l != 4) { + DEBUG_TRACE(printf("BUG! r.ip with port\n")); + return; + } + p->r.ip = (struct bt_ipv4p *)s; + return; + } + if(STREQ(cbd->buf,"r.token")) { + p->r.token = s; + p->r.t_len = cbd->v.s.l; + return; + } + if(STREQ(cbd->buf,"r.values")) { + if(cbd->v.s.l == 18) { + if(!p->r.values6) { + p->r.values6 = s; + p->r.nv6 = 1; + } else { + if(s != p->r.values6+(p->r.nv6*21)) { + // DEBUG_TRACE(printf("BUG! r.values6 not in list! %08x %08x \n", p->r.values+(p->r.nv6*21),s)); + return; + } + p->r.nv6++; + } + return; + } + if(cbd->v.s.l == 6) { + if(!p->r.values) { + p->r.values = s; + p->r.nv = 1; + } else { + if(s != p->r.values+(p->r.nv*8)) { + // DEBUG_TRACE(printf("BUG! r.values not in list! %u \n",s-p->r.values+(p->r.nv*8))); + return; + } + p->r.nv++; + } + return; + } + return; + } + + if(STREQ(cbd->buf,"r.name") || STREQ(cbd->buf,"r.n")) { + p->r.name = s; + p->r.name_len = cbd->v.s.l; + return; + } + if(STREQ(cbd->buf,"r.nodes")) { + if(cbd->v.s.l % 26) { + // DEBUG_TRACE(printf("BUG! r.nodes length %d not %% 26\n",cbd->v.s.l)); + return; + } + p->r.nodes = (struct bt_nodes_data *)s; + p->r.nn = cbd->v.s.l / 26; + return; + } + if(STREQ(cbd->buf,"r.nodes6")) { + if(cbd->v.s.l % 38) { + // DEBUG_TRACE(printf("BUG! r.nodes length %d not %% 38\n",cbd->v.s.l)); + return; + } + p->r.nodes6 = (struct bt_nodes6_data *)s; + p->r.nn6 = cbd->v.s.l / 38; + return; + } + + if(cbd->buf[0] == 'y' && !cbd->buf[1]) { + if(cbd->v.s.l != 1) return; + if(*ss == 'q') { p->y_q = 1; return; } + if(*ss == 'r') { p->y_r = 1; return; } + if(*ss == 'e') { p->y_e = 1; return; } + return; + } + if(cbd->buf[0] == 'q' && !cbd->buf[1]) { + if(!strncmp(ss,"announce_peer",13)) { + p->q_a_peer = 1; + return; + } + if(!strncmp(ss,"find_node",9)) { + p->q_f_node = 1; + return; + } + if(!strncmp(ss,"get_peers",9)) { + p->q_g_peers = 1; + return; + } + if(!strncmp(ss,"ping",4)) { + p->q_ping = 1; + return; + } + if(!strncmp(ss,"vote",4)) { + return; + } + } + if(STREQ(cbd->buf,"ip")) { + if(cbd->v.s.l != 6) { + // DEBUG_TRACE(printf("BUG! r.ip w/o port\n")); + } + p->ip = (struct bt_ipv4p *)s; + p->h_ip = 1; + return; + } + if(STREQ(cbd->buf,"peers")) { + if(cbd->v.s.l % 6) return; + p->peers = (struct bt_ipv4p *)s; + p->n_peers = cbd->v.s.l / 6; + return; + } + if((*cbd->buf == 't' || *cbd->buf == 'v') && !cbd->buf[1]) { + u_int64_t d = *(u_int64_t*)s; + switch(cbd->v.s.l) { + case 2: + d &= 0xffffllu; d = htons(d); break; + case 4: + d &= 0xffffffffllu; d = htonl(d); break; + case 6: + d &= 0xffffffffffffllu; d = (htonl(d & 0xffffffff) << 16) | + (htons(d >> 32) & 0xffff); + break; + case 8: d = ((u_int64_t)htonl(d & 0xffffffff) << 32) | + htonl(d >> 32); + break; + default: d = 0; + } + if(*cbd->buf == 'v') cbd->p.v = d; + else cbd->p.t = d; + return; + } + + if(cbd->buf[0] == 'e' && !cbd->buf[0]) { + p->e_msg = s; + p->e_len = cbd->v.s.l; + return; + } + // DEBUG_TRACE(print_safe_str("UKNOWN",cbd)); +} + + +const u_int8_t *bt_decode(const u_int8_t *b, size_t *l, int *ret, bt_parse_data_cb_t *cbd) { + + unsigned int n=0,neg=0; + i_int64_t d = 0; + register u_int8_t c; + + if(*l == 0) return NULL; + if(cbd->level > BDEC_MAXDEPT) goto bad_data; + c = *b++; (*l)--; + if(c == 'i') { // integer + while(*l) { + c = *b++; (*l)--; + n++; + if(c == '-') { + if(n != 1) goto bad_data; + n--; + neg=1; + continue; + } + if(c >= '0' && c <= '9') { + if(c == '0' && n > 1 && !d && *b != 'e') goto bad_data; + d *= 10; + d += c-'0'; + continue; + } + if(c != 'e') goto bad_data; + break; + } + if(neg) d=-d; + cbd->t = 1; + cbd->v.i = neg ? -d:d; + return b; + } + if(c >= '1' && c <= '9') { //string + d=c-'0'; + while(*l) { + c = *b++; (*l)--; + n++; + if(c >= '0' && c <= '9') { + if(c == '0' && n > 1 && d == 0) goto bad_data; + d *= 10; + d += c-'0'; + continue; + } + if(c != ':') goto bad_data; + break; + } + if(d > *l) goto bad_data; + cbd->t = 2; + cbd->v.s.s = b; + cbd->v.s.l = d; + b += d; + *l -= d; + return b; + } + if(c == 'l') { + cbd->level++; + do { + b = bt_decode(b,l,ret,cbd); + if(*ret < 0 || *l == 0) goto bad_data; + cb_data(cbd,ret); + if(*ret < 0) goto bad_data; + cbd->t = 0; + } while (*b != 'e' && *l != 0); + b++; (*l)--; + cbd->level--; + return b; + } + if(c == 'd') { + cbd->level++; + do { + char *ls = cbd->buf + strlen(cbd->buf); + int l1 = ls != cbd->buf ? 1:0; + if(!(*b >= '1' && *b <= '9')) goto bad_data; + b = bt_decode(b,l,ret,cbd); + if(*ret < 0 || *l == 0) goto bad_data; + if(ls+cbd->v.s.l+l1 < &cbd->buf[sizeof(cbd->buf)-1]) { + if(l1) ls[0]='.'; + strncpy(ls+l1,(char *)cbd->v.s.s,cbd->v.s.l); + ls[cbd->v.s.l+l1]=0; + } + b = bt_decode(b,l,ret,cbd); + if(*ret < 0 || *l == 0) goto bad_data; + cb_data(cbd,ret); + if(*ret < 0) goto bad_data; + cbd->t = 0; + *ls = 0; + } while (*b != 'e' && l != 0); + + b++; (*l)--; + cbd->level--; + return b; + } + bad_data: + *ret=-1; + return b; +} |