int ben_str_compare(BEN * key1, BEN * key2) { LONG size = 0; LONG i = 0; if (!ben_is_str(key1)) { return -1; } if (!ben_is_str(key2)) { return 1; } size = (key1->v.s->i > key2->v.s->i) ? key1->v.s->i : key2->v.s->i; for (i = 0; i < size; i++) { if (key1->v.s->s[i] > key2->v.s->s[i]) { return 1; } else if (key1->v.s->s[i] < key2->v.s->s[i]) { return -1; } } /* Strings are equal for the first $size characters */ if (key1->v.s->i > key2->v.s->i) { return 1; } else if (key1->v.s->i < key2->v.s->i) { return -1; } /* Equal */ return 0; }
void p2p_error(BEN * packet, IP * from) { BEN *e = NULL; BEN *code = NULL; BEN *msg = NULL; ITEM *i = NULL; #if 0 BEN *t = NULL; /* Transaction ID */ t = ben_dict_search_str(packet, "t"); if (!ben_is_str(t)) { info(_log, from, "Missing transaction ID from"); return; } if (ben_str_i(t) != TID_SIZE) { info(_log, from, "Broken transaction ID from"); return; } #endif /* The error */ e = ben_dict_search_str(packet, "e"); if (!ben_is_list(e)) { info(_log, from, "Missing or broken error message from"); return; } /* Error code */ i = list_start(e->v.l); code = list_value(i); if (!ben_is_int(code)) { info(_log, from, "Broken error code from"); return; } /* Error message */ i = list_stop(e->v.l); msg = list_value(i); if (!ben_is_str(msg)) { info(_log, from, "Broken error message from"); return; } if (ben_str_i(msg) > 100) { info(_log, from, "Error message too big from"); return; } /* Notification */ info(_log, from, "ERROR %li: \"%s\" from", code->v.i, ben_str_s(msg)); }
void p2p_get_peers_get_reply(BEN * arg, UCHAR * node_id, ITEM * ti, IP * from) { BEN *token = NULL; BEN *nodes = NULL; BEN *values = NULL; token = ben_dict_search_str(arg, "token"); if (!ben_is_str(token)) { info(_log, from, "Missing or broken token from"); return; } else if (ben_str_i(token) > TOKEN_SIZE_MAX) { info(_log, from, "Token key too big from"); return; } else if (ben_str_i(token) <= 0) { info(_log, from, "Invalid token from"); return; } values = ben_dict_search_str(arg, "values"); #ifdef IPV6 nodes = ben_dict_search_str(arg, "nodes6"); #elif IPV4 nodes = ben_dict_search_str(arg, "nodes"); #endif if (values != NULL) { if (!ben_is_list(values)) { info(_log, NULL, "values key missing or broken"); return; } else { p2p_get_peers_get_values(values, node_id, ti, token, from); return; } } if (nodes != NULL) { if (!ben_is_str(nodes)) { info(_log, NULL, "nodes key missing"); return; } else if (ben_str_i(nodes) % IP_SIZE_META_TRIPLE != 0) { info(_log, NULL, "nodes key broken"); return; } else { p2p_get_peers_get_nodes(nodes, node_id, ti, token, from); return; } } }
void handle_message(cjdnsadmin_t *adm, char *buffer, ssize_t len) { // TODO: fix memory leak struct bencode *b = ben_decode(buffer, len); if (!b) { fprintf(stderr, "bencode error: %lu\n",len); printf("message from cjdns: \"%*s\"\n", (int)len, buffer); return; } // Get IPs struct bencode *table = ben_dict_get_by_str(b, "routingTable"); size_t i, num_items = ben_list_len(table); for (i = 0; i < num_items; i++) { struct bencode *item = ben_list_get(table, i); struct bencode *ip = ben_dict_get_by_str(item, "ip"); if (ben_is_str(ip)) { const char *ip_str = ben_str_val(ip); if (adm->on_found_ip) { (*adm->on_found_ip)(adm->on_found_ip_obj, ip_str); } } } // check if there is more struct bencode *more = ben_dict_get_by_str(b, "more"); int more_int = more && ben_is_int(more) && ben_int_val(more); if (more_int == 1) { // get the next page of the routing table adm->fetch_peers_page++; cjdnsadmin_fetch_peers(adm); } else { // start from the first page next time adm->fetch_peers_page = 0; } ben_free(b); }
int p2p_is_port(BEN * node) { if (node == NULL) { return 0; } if (!ben_is_str(node)) { return 0; } if (ben_str_i(node) != 2) { return 0; } return 1; }
int p2p_is_ip(BEN * node) { if (node == NULL) { return 0; } if (!ben_is_str(node)) { return 0; } if (ben_str_i(node) != IP_SIZE) { return 0; } return 1; }
int p2p_is_hash(BEN * node) { if (node == NULL) { return 0; } if (!ben_is_str(node)) { return 0; } if (ben_str_i(node) != SHA1_SIZE) { return 0; } return 1; }
void p2p_find_node_get_reply(BEN * arg, UCHAR * node_id, IP * from) { BEN *nodes = NULL; UCHAR *id = NULL; UCHAR *p = NULL; long int i = 0; IP sin; #ifdef IPV6 nodes = ben_dict_search_str(arg, "nodes6"); #elif IPV4 nodes = ben_dict_search_str(arg, "nodes"); #endif if (!ben_is_str(nodes)) { info(_log, NULL, "nodes key missing"); return; } if (ben_str_i(nodes) % IP_SIZE_META_TRIPLE != 0) { info(_log, NULL, "nodes key broken"); return; } p = ben_str_s(nodes); for (i = 0; i < ben_str_i(nodes); i += IP_SIZE_META_TRIPLE) { /* ID */ id = p; p += SHA1_SIZE; /* IP + Port */ p = ip_tuple_to_sin(&sin, p); /* Ignore myself */ if (node_me(id)) { continue; } /* Ignore link-local address */ if (ip_is_linklocal(&sin)) { continue; } /* Store node */ nbhd_put(id, &sin); } }
void p2p_decode(UCHAR * bencode, size_t bensize, IP * from) { BEN *packet = NULL; BEN *y = NULL; /* Parse request */ packet = ben_dec(bencode, bensize); if (packet == NULL) { info(_log, from, "Decoding UDP packet failed:"); return; } else if (packet->t != BEN_DICT) { info(_log, from, "UDP packet is not a dictionary:"); ben_free(packet); return; } /* Type of message */ y = ben_dict_search_str(packet, "y"); if (!ben_is_str(y) || ben_str_i(y) != 1) { info(_log, from, "Message type missing or broken:"); ben_free(packet); return; } mutex_block(_main->work->mutex); switch (*y->v.s->s) { case 'q': p2p_request(packet, from); break; case 'r': p2p_reply(packet, from); break; case 'e': p2p_error(packet, from); break; default: info(_log, from, "Drop invalid message type '%c' from", *y->v.s->s); } mutex_unblock(_main->work->mutex); ben_free(packet); }
void p2p_announce_get_request(BEN * arg, UCHAR * node_id, BEN * tid, IP * from) { BEN *info_hash = NULL; BEN *token = NULL; BEN *port = NULL; /* info_hash */ info_hash = ben_dict_search_str(arg, "info_hash"); if (!p2p_is_hash(info_hash)) { info(_log, from, "Missing or broken info_hash from"); return; } /* Token */ token = ben_dict_search_str(arg, "token"); if (!ben_is_str(token) || ben_str_i(token) > TOKEN_SIZE_MAX) { info(_log, from, "Missing or broken token from"); return; } if (!tkn_validate(ben_str_s(token))) { info(_log, from, "Invalid token from"); return; } /* Port */ port = ben_dict_search_str(arg, "port"); if (!ben_is_int(port)) { info(_log, from, "Missing or broken port from"); return; } if (port->v.i < 1 || port->v.i > 65535) { info(_log, from, "Invalid port number from"); return; } /* Store info_hash */ val_put(ben_str_s(info_hash), node_id, port->v.i, from); /* Send success message */ send_announce_reply(from, ben_str_s(tid), ben_str_i(tid)); }
void p2p_get_peers_get_values(BEN * values, UCHAR * node_id, ITEM * ti, BEN * token, IP * from) { UCHAR nodes_compact_list[IP_SIZE_META_PAIR8]; UCHAR *p = nodes_compact_list; LOOKUP *l = tdb_ldb(ti); int nodes_compact_size = 0; BEN *val = NULL; ITEM *item = NULL; long int j = 0; char hex[HEX_LEN]; if (l == NULL) { return; } ldb_update(l, node_id, token, from); /* Extract values and create a nodes_compact_list */ item = list_start(values->v.l); while (item != NULL && j < 8) { val = list_value(item); if (!ben_is_str(val) || ben_str_i(val) != IP_SIZE_META_PAIR) { info(_log, from, "Values list broken from "); return; } memcpy(p, ben_str_s(val), ben_str_i(val)); nodes_compact_size += IP_SIZE_META_PAIR; p += IP_SIZE_META_PAIR; item = list_next(item); j++; } if (nodes_compact_size <= 0) { return; } hex_hash_encode(hex, l->target); info(_log, from, "Found %s at", hex); /* * Random lookups are not initiated by a client. * Periodic announces are not initiated by a client either. * And I do not want to cache random lookups. */ if (!l->send_response_to_initiator) { return; } /* Merge responses to the cache */ cache_put(l->target, nodes_compact_list, nodes_compact_size); /* Do not send more than one DNS response to a client. * The client is happy after getting the first response anyway. */ if (ldb_number_of_dns_responses(l) >= 1) { return; } /* Get the merged compact list from the cache. */ nodes_compact_size = cache_compact_list(nodes_compact_list, l->target); if (nodes_compact_size <= 0) { return; } /* Send the result back via DNS */ r_success(&l->c_addr, &l->msg, nodes_compact_list, nodes_compact_size); }
void p2p_reply(BEN * packet, IP * from) { BEN *r = NULL; BEN *t = NULL; BEN *id = NULL; ITEM *ti = NULL; /* Argument */ r = ben_dict_search_str(packet, "r"); if (!ben_is_dict(r)) { info(_log, from, "Argument missing or broken:"); return; } /* Node ID */ id = ben_dict_search_str(r, "id"); if (!p2p_is_hash(id)) { info(_log, from, "Node ID missing or broken:"); return; } /* Do not talk to myself */ if (p2p_packet_from_myself(ben_str_s(id))) { return; } /* Transaction ID */ t = ben_dict_search_str(packet, "t"); if (!ben_is_str(t)) { info(_log, from, "Missing transaction ID from"); return; } if (ben_str_i(t) != TID_SIZE) { info(_log, from, "Broken transaction ID from"); return; } /* Remember node. */ nbhd_put(ben_str_s(id), (IP *) from); ti = tdb_item(ben_str_s(t)); /* Get Query type by looking at the TDB */ switch (tdb_type(ti)) { case P2P_PING: case P2P_PING_MULTICAST: p2p_pong(ben_str_s(id), from); break; case P2P_FIND_NODE: p2p_find_node_get_reply(r, ben_str_s(id), from); break; case P2P_GET_PEERS: case P2P_ANNOUNCE_START: p2p_get_peers_get_reply(r, ben_str_s(id), ti, from); break; case P2P_ANNOUNCE_ENGAGE: p2p_announce_get_reply(r, ben_str_s(id), ti, from); break; default: info(_log, from, "Invalid Transaction ID from"); return; } /* Cleanup. The TID gets reused by GET_PEERS and ANNOUNCE_PEER requests. * The TID is also persistant for multicast requests since multiple * answers are likely possible. */ switch (tdb_type(ti)) { case P2P_PING: case P2P_FIND_NODE: case P2P_ANNOUNCE_ENGAGE: tdb_del(ti); break; } }
void p2p_request(BEN * packet, IP * from) { BEN *q = NULL; BEN *a = NULL; BEN *t = NULL; BEN *id = NULL; /* Query Type */ q = ben_dict_search_str(packet, "q"); if (!ben_is_str(q)) { info(_log, from, "Query type missing or broken:"); return; } /* Argument */ a = ben_dict_search_str(packet, "a"); if (!ben_is_dict(a)) { info(_log, from, "Argument missing or broken:"); return; } /* Node ID */ id = ben_dict_search_str(a, "id"); if (!p2p_is_hash(id)) { info(_log, from, "Node ID missing or broken:"); return; } /* Do not talk to myself */ if (p2p_packet_from_myself(ben_str_s(id))) { return; } /* Transaction ID */ t = ben_dict_search_str(packet, "t"); if (!ben_is_str(t)) { info(_log, from, "Transaction ID missing or broken:"); return; } if (ben_str_i(t) > TID_SIZE_MAX) { info(_log, from, "Transaction ID too big:"); return; } /* Remember node. This does not update the IP address. */ nbhd_put(ben_str_s(id), from); /* PING */ if (ben_str_i(q) == 4 && memcmp(ben_str_s(q), "ping", 4) == 0) { p2p_ping(t, from); return; } /* FIND_NODE */ if (ben_str_i(q) == 9 && memcmp(ben_str_s(q), "find_node", 9) == 0) { p2p_find_node_get_request(a, t, from); return; } /* GET_PEERS */ if (ben_str_i(q) == 9 && memcmp(ben_str_s(q), "get_peers", 9) == 0) { p2p_get_peers_get_request(a, t, from); return; } /* ANNOUNCE */ if (ben_str_i(q) == 13 && memcmp(ben_str_s(q), "announce_peer", 13) == 0) { p2p_announce_get_request(a, ben_str_s(id), t, from); return; } /* VOTE (utorrent?) */ if (ben_str_i(q) == 4 && memcmp(ben_str_s(q), "vote", 4) == 0) { info(_log, from, "Drop RPC VOTE message from"); return; } info(_log, from, "Drop invalid query type from"); }
void p2p_decrypt(UCHAR * bencode, size_t bensize, IP * from) { BEN *packet = NULL; BEN *salt = NULL; BEN *aes = NULL; struct obj_str *plain = NULL; /* Parse request */ packet = ben_dec(bencode, bensize); if (!ben_is_dict(packet)) { info(_log, from, "Decoding AES packet failed:"); ben_free(packet); return; } /* Salt */ salt = ben_dict_search_str(packet, "s"); if (!ben_is_str(salt) || ben_str_i(salt) != AES_IV_SIZE) { info(_log, from, "Salt missing or broken:"); ben_free(packet); return; } /* Encrypted AES message */ aes = ben_dict_search_str(packet, "a"); if (!ben_is_str(aes) || ben_str_i(aes) <= 2) { info(_log, from, "AES message missing or broken:"); ben_free(packet); return; } /* Decrypt message */ plain = aes_decrypt(ben_str_s(aes), ben_str_i(aes), ben_str_s(salt), _main->conf->key, strlen(_main->conf->key)); if (plain == NULL) { info(_log, from, "Decoding AES message failed:"); ben_free(packet); return; } /* AES packet too small */ if (plain->i < SHA1_SIZE) { ben_free(packet); str_free(plain); info(_log, from, "AES packet contains less than 20 bytes:"); return; } /* Validate bencode */ if (!ben_validate(plain->s, plain->i)) { ben_free(packet); str_free(plain); info(_log, from, "AES packet contains broken bencode:"); return; } /* Parse message */ p2p_decode(plain->s, plain->i, from); /* Free */ ben_free(packet); str_free(plain); }