Exemple #1
0
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;
}
Exemple #2
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));
}
Exemple #3
0
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;
		}
	}
}
Exemple #4
0
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);
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}
Exemple #8
0
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);
	}
}
Exemple #9
0
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);
}
Exemple #10
0
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));
}
Exemple #11
0
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);
}
Exemple #12
0
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;
	}
}
Exemple #13
0
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");
}
Exemple #14
0
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);
}