int send_packet(const byte buffer[], byte len, void (*send_cb)(byte[], byte len)) { int byte_counter=0; byte *payload_buf = (byte *)malloc(len*2); byte actual_length_payload = escape_buffer(buffer, payload_buf, len); byte actual_length_buf[2]; // we also need to escape the length byte byte actual_length_length = escape_buffer(&len, actual_length_buf, 1); send_cb(&start_byte, 1); send_cb(actual_length_buf, actual_length_length); send_cb(payload_buf, actual_length_payload); send_cb(&stop_byte, 1); free(payload_buf); byte_counter += (1 + 1 + actual_length_length + actual_length_payload); return byte_counter; }
int botnet_send_file(BOTNET_REC *botnet, const char *target, const char *fname) { GNode *node; GString *str; char buffer[1024]; int f, len; node = bot_find_path(botnet, target); if (node == NULL) { g_warning("Can't find route for target %s", target); return FALSE; } f = open(fname, O_RDONLY); if (f == -1) return FALSE; str = g_string_new(NULL); g_string_sprintf(str, "%s %s FILE %s", botnet->nick, target, g_basename(fname)); bot_send_cmd(node->data, str->str); while ((len = read(f, buffer, sizeof(buffer)/2-2)) > 0) { escape_buffer(buffer, len); g_string_sprintf(str, "%s %s FILE %s", botnet->nick, target, buffer); bot_send_cmd(node->data, str->str); } g_string_sprintf(str, "%s %s FILE", botnet->nick, target); bot_send_cmd(node->data, str->str); g_string_free(str, TRUE); close(f); return TRUE; }
static void handle_vmsg_time_sync_reply(const struct gnutella_header *header, const char *data, size_t size) { if (size < 17) { printf("Too short: %s\n", escape_buffer(data, size)); } else { bool used_ntp = data[8] & 0x1; char buf[32], *p; printf("NTP: %s\n", used_ntp ? "yes" : "no"); p = print_iso8601_date(buf, sizeof buf, peek_be32(&header->guid.data[0])); *p = '\0'; printf("T1: %s (%lu us)\n", buf, (unsigned long) peek_be32(&header->guid.data[4])); p = print_iso8601_date(buf, sizeof buf, peek_be32(&data[9])); *p = '\0'; printf("T2: %s (%lu us)\n", buf, (unsigned long) peek_be32(&data[13])); p = print_iso8601_date(buf, sizeof buf, peek_be32(&header->guid.data[8])); *p = '\0'; printf("T3: %s (%lu us)\n", buf, (unsigned long) peek_be32(&header->guid.data[12])); if (size > 17) { handle_extension(&data[17], size - 17); } } }
static void handle_extension(const char * const data, const size_t size) { if (size > 0) { const char *g_ptr; g_ptr = memchr(data, GGEP_MAGIC, size); if (g_ptr) { size_t g_len = &data[size] - g_ptr; handle_ggep(g_ptr, g_len); } printf("Raw data: \"%s\"\n", escape_buffer(data, size)); } }
static void handle_vmsg_oob_reply(const struct gnutella_header *header, const char *data, size_t size) { (void) header; if (size < 9) { printf("Too short: %s\n", escape_buffer(data, size)); } else { printf("Hits: %u\n", (uint8_t) data[8]); if (size > 9) { handle_extension(&data[9], size - 9); } } }
static void handle_pong(const char * const data, const size_t size) { if (size < 14) { printf("Too short: %s\n", escape_buffer(data, size)); } else { printf("Source: %s\n", net_addr_port_to_string(net_addr_peek_ipv4(&data[2]), peek_le16(data))); printf("Files: %lu\n", (unsigned long) peek_le32(&data[6])); printf("Volume: %lu KiB\n", (unsigned long) peek_le32(&data[10])); if (size > 14) { handle_extension(&data[14], size - 14); } } }
static void handle_ggep_h(const char *data, size_t size) { static const struct { const char * const prefix; const uint8_t base; } hashes[] = { { NULL, 0 }, { "urn:sha1:", 32 }, { "urn:bitprint:", 32 }, { "urn:md5:", 64 }, { "urn:uuid:", 16 }, { "urn:md4:", 64 }, }; unsigned char h; const char *prefix; uint8_t base; if (size < 1) { printf(" <No payload>"); return; } h = data[0]; if (h < ARRAY_LEN(hashes)) { prefix = hashes[h].prefix; base = hashes[h].base; } else { prefix = NULL; base = 0; } if (prefix && base) { printf(": %s", prefix); if (32 == base) { char base32[256]; size_t base32_len; base32_len = base32_encode(base32, sizeof base32, &data[1], size - 1); base32[base32_len] = '\0'; printf("%s", base32); } } else { printf(": <%u> \"%s\"", h, escape_buffer(&data[1], size - 1)); } }
static void handle_vmsg_time_sync_request(const struct gnutella_header *header, const char *data, size_t size) { (void) header; if (size < 9) { printf("Too short: %s\n", escape_buffer(data, size)); } else { bool used_ntp = data[8] & 0x1; printf("NTP: %s\n", used_ntp ? "yes" : "no"); if (size > 9) { handle_extension(&data[9], size - 9); } } }
static void handle_vmsg_priv(const struct gnutella_header *header, const char *data, size_t size) { if (size < 8) { printf("Too short: %s\n", escape_buffer(data, size)); } else { char vendor[32], *p; size_t vendor_size = sizeof vendor; struct vmsg_head vh; unsigned i; p = append_escaped_chars(vendor, &vendor_size, data, 4); *p = '\0'; vh.vendor = peek_be32(&data[0]); vh.selector = peek_le16(&data[4]); vh.version = peek_le16(&data[6]); printf("%s/%uv%u", vendor, vh.selector, vh.version); for (i = 0; i < ARRAY_LEN(vmsg_table); i++) { if ( vmsg_table[i].vendor == vh.vendor && vmsg_table[i].selector == vh.selector && vmsg_table[i].version == vh.version ) { printf(" %s\n", vmsg_table[i].name); vmsg_table[i].handler(header, data, size); break; } } if (ARRAY_LEN(vmsg_table) == i) { printf("\n"); handle_extension(&data[8], size - 8); } } }
static void handle_query(const struct gnutella_header *header, const char * const data, const size_t size) { const char *end; if (size < 2) { printf("Too short: %s\n", escape_buffer(data, size)); } else { uint16_t flags; int swapped = 0; flags = peek_be16(data); if (!(flags & QUERY_F_MARK)) { uint16_t mask = QUERY_F_MARK | QUERY_F_GGEP_H | QUERY_F_LEAF_GUIDED; uint16_t reversed; /* Try to decode endian swapped flags as emitted by RAZA */ reversed = peek_le16(data); if ((reversed & mask) == mask) { swapped = 1; flags = reversed; } } if (flags & QUERY_F_MARK) { int is_firewalled = flags & QUERY_F_FIREWALLED; int want_xml = flags & QUERY_F_WANT_XML; int leaf_guided = flags & QUERY_F_LEAF_GUIDED; int ggep_h = flags & QUERY_F_GGEP_H; int is_oob = flags & QUERY_F_OOB; int rudp_supp = flags & QUERY_F_RUDP; int bit8 = flags & QUERY_F_BIT8; printf("Flags: %s%s%s%s%s%s%s%s\n" , is_firewalled ? "firewalled " : "" , want_xml ? "XML " : "" , leaf_guided ? "leaf-guided " : "" , ggep_h ? "GGEP/H " : "" , is_oob ? "OOB " : "" , rudp_supp ? "RUDP " : "" , bit8 ? "bit8 " : "" , swapped ? "[SWAPPED]" : "" ); if (is_oob) { printf("OOB address: %s\n", net_addr_port_to_string(net_addr_peek_ipv4(&header->guid.data[0]), peek_le16(&header->guid.data[13])) ); } } else { printf("Flags: 0x%04X\n", flags); } end = memchr(&data[2], '\0', size - 2); if (end) { end++; } else { end = &data[size]; } printf("Query: \"%s\"\n", escape_buffer(&data[2], (end - &data[2]) - 1)); if (&data[size] != end) { size_t ext_len; ext_len = &data[size] - end; if ('\0' == data[size - 1]) { ext_len--; } handle_extension(end, ext_len); } } }
static void handle_qhit(const char *data, size_t size) { const struct gnutella_qhit_header *header; const struct gnutella_guid *guid; const struct gnutella_qhit_item *item; size_t guid_offset = size - sizeof *guid; unsigned hits; size_t pos; RUNTIME_ASSERT(size <= GNUTELLA_MAX_PAYLOAD); if (size < sizeof *header) { fprintf(stderr, "handle_qhit(): Too little payload for header.\n"); return; } header = cast_to_const_void_ptr(data); hits = (unsigned char) header->hits; printf("Hits: %u\n", hits); printf("Address: %s\n", net_addr_port_to_string(net_addr_peek_ipv4(cast_to_const_char_ptr(header->addr)), peek_le16(header->port))); printf("Speed: %lu\n", (unsigned long) peek_le32(header->speed)); if (size < sizeof *header + sizeof *guid) { fprintf(stderr, "handle_qhit(): Insufficient payload for query hit.\n"); return; } if (size >= sizeof *header + sizeof *guid) { guid = cast_to_const_void_ptr(&data[guid_offset]); printf("Servent ID: %08lx-%08lx-%08lx-%08lx\n", (unsigned long) peek_be32(&guid->data[0]), (unsigned long) peek_be32(&guid->data[4]), (unsigned long) peek_be32(&guid->data[8]), (unsigned long) peek_be32(&guid->data[12])); } printf("----\n"); pos = sizeof *header; for (/* NOTHING */; hits > 0; hits--) { const char *nul_ptr; if (pos >= guid_offset || guid_offset - pos < sizeof *item + 2) break; item = cast_to_const_void_ptr(&data[pos]); printf("Index: %lu\n", (unsigned long) peek_le32(item->index)); printf("Size: %lu\n", (unsigned long) peek_le32(item->size)); pos += sizeof *item; nul_ptr = memchr(&data[pos], 0, guid_offset - pos); if (!nul_ptr) { fprintf(stderr, "handle_qhit(): Non-terminated filename.\n"); return; } else { size_t len; len = (nul_ptr - &data[pos]); if (len > (((size_t) -1) / 4 - 1)) { fprintf(stderr, "handle_qhit(): Filename is too long.\n"); /* Ignore */ } else { const char *p; size_t avail; printf("Filename: "); avail = len; p = &data[pos]; while (avail > 0) { uint32_t cp; cp = utf8_decode(p, avail); if ((uint32_t) -1 != cp) { uint8_t u_len, i; u_len = utf8_first_byte_length_hint((unsigned char) *p); RUNTIME_ASSERT(u_len > 0); RUNTIME_ASSERT(avail >= u_len); avail -= u_len; if (cp >= 0x20 && cp != 0x7f) { for (i = 0; i < u_len; i++) { putchar((unsigned char) p[i]); } } else { char ch = cp & 0xff; printf("%s", escape_buffer(&ch, 1)); } p += u_len; } else { if (verbosity > 0) { fprintf(stderr, "handle_qhit(): Invalid UTF-8.\n"); } break; } } } printf("\n"); pos += len; } RUNTIME_ASSERT(nul_ptr); RUNTIME_ASSERT(&data[pos] == nul_ptr); RUNTIME_ASSERT('\0' == *nul_ptr); pos++; RUNTIME_ASSERT(pos <= guid_offset); nul_ptr = memchr(&data[pos], 0, guid_offset - pos); if (!nul_ptr) { fprintf(stderr, "handle_qhit(): Non-terminated extension block.\n"); return; } else if (nul_ptr != &data[pos]) { size_t len = nul_ptr - &data[pos]; printf("Extension size: %lu\n", (unsigned long) len); handle_extension(&data[pos], len); pos += len; } RUNTIME_ASSERT(nul_ptr); RUNTIME_ASSERT(&data[pos] == nul_ptr); RUNTIME_ASSERT('\0' == *nul_ptr); pos++; RUNTIME_ASSERT(pos <= guid_offset); printf("------\n"); } if (hits > 0) { fprintf(stderr, "handle_qhit(): Expected %u more hits.\n", hits); } if (pos < guid_offset) { static const unsigned vendor_id_len = 4; printf("Extended QHD size: %lu\n", (unsigned long) guid_offset - pos); if (guid_offset - pos >= vendor_id_len) { printf("Vendor ID: %s\n", escape_buffer(&data[pos], vendor_id_len)); pos += vendor_id_len; if (pos < guid_offset) { uint8_t open_data_size = data[pos]; bool has_ggep = false; printf("Open data size: %u\n", open_data_size); pos++; if (open_data_size > guid_offset - pos) { printf("Open data size is too large.\n"); return; } if (open_data_size >= 2) { uint8_t mask = data[pos]; uint8_t value = data[pos + 1]; printf("mask: 0x%02x\n", mask); printf("value: 0x%02x\n", value); if (0x20 & mask) { has_ggep = 0x20 & value; printf("Has GGEP: %s\n", has_ggep ? "yes" : "no"); } if (0x10 & mask) { printf("Has speed: %s\n", (0x10 & value) ? "yes" : "no"); } if (0x08 & mask) { printf("Has uploaded: %s\n", (0x08 & value) ? "yes" : "no"); } if (0x04 & mask) { printf("Busy: %s\n", (0x04 & value) ? "yes" : "no"); } /* mask and value are swapped */ if (0x01 & value) { printf("Must push: %s\n", (0x01 & mask) ? "yes" : "no"); } } pos += open_data_size; if (pos < guid_offset) { size_t priv_data_size = guid_offset - pos; static const char id_deflate[] = "{deflate}"; const char *priv_data, *x; priv_data = &data[pos]; priv_data_size = guid_offset - pos; printf("Private data area size: %lu\n", (unsigned long) priv_data_size); handle_extension(priv_data, priv_data_size); x = compat_memmem(priv_data, priv_data_size, id_deflate, STATIC_STRLEN(id_deflate)); if (x) { char buf[64 * 1024]; const char *src; size_t n, src_len; src = &x[STATIC_STRLEN(id_deflate)]; src_len = priv_data_size - STATIC_STRLEN(id_deflate); n = buffer_inflate(buf, sizeof buf, src, src_len); if ((size_t) -1 != n) { printf("Inflated: %s\n", escape_buffer(buf, n)); } } pos += priv_data_size; } RUNTIME_ASSERT(pos == guid_offset); } } } printf("----\n"); }
static int handle_ggep(const char *data, size_t size) { char ggep_buf[4096]; ggep_t gtx; if (!ggep_decode(>x, data, size)) { return -1; } for (;;) { char id_name[GGEP_ID_BUFLEN]; const char *data_ptr; size_t data_len; ggep_id_t id; int ret; ret = ggep_next(>x, id_name); if (0 == ret) break; if (-1 == ret) { /* Could not get next GGEP block */ break; } printf("GGEP \"%s\"", id_name); id = ggep_map_id_name(id_name, NULL); if (GGEP_ID_INVALID == id) { printf(" <Unknown GGEP ID>\n"); } data_len = ggep_data(>x, &data_ptr, ggep_buf, sizeof ggep_buf); if ((size_t) -1 == data_len) { if (verbosity > 0) { fprintf(stderr, "Decoding of GGEP block failed\n"); } printf("<GGEP decoding failure>\n"); continue; } switch (id) { case GGEP_ID_ALT: handle_ggep_alt(data_ptr, data_len); break; case GGEP_ID_CT: handle_ggep_ct(data_ptr, data_len); break; case GGEP_ID_DU: handle_ggep_du(data_ptr, data_len); break; case GGEP_ID_H: handle_ggep_h(data_ptr, data_len); break; case GGEP_ID_IPP: handle_ggep_ipp(data_ptr, data_len); break; case GGEP_ID_IP: handle_ggep_ip(data_ptr, data_len); break; case GGEP_ID_UDPNFW: handle_ggep_udpnfw(data_ptr, data_len); break; case GGEP_ID_M: handle_ggep_m(data_ptr, data_len); break; case GGEP_ID_PUSH: handle_ggep_push(data_ptr, data_len); break; default: if (data_len > 0) { printf(" raw data (%lu bytes): \"%s\"", (unsigned long) data_len, escape_buffer(data_ptr, data_len)); } else { printf(" <No payload>"); } } printf("\n"); } return 0; }