Пример #1
0
bool ans_key_h(connection_t *c) {
	char from_name[MAX_STRING_SIZE];
	char to_name[MAX_STRING_SIZE];
	char key[MAX_STRING_SIZE];
	char address[MAX_STRING_SIZE] = "";
	char port[MAX_STRING_SIZE] = "";
	int cipher, digest, maclength, compression;
	node_t *from, *to;

	if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
		from_name, to_name, key, &cipher, &digest, &maclength,
		&compression, address, port) < 7) {
		logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
			   c->hostname);
		return false;
	}

	if(!check_id(from_name) || !check_id(to_name)) {
		logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_KEY", c->name, c->hostname, "invalid name");
		return false;
	}

	from = lookup_node(from_name);

	if(!from) {
		logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
			   "ANS_KEY", c->name, c->hostname, from_name);
		return true;
	}

	to = lookup_node(to_name);

	if(!to) {
		logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
			   "ANS_KEY", c->name, c->hostname, to_name);
		return true;
	}

	/* Forward it if necessary */

	if(to != myself) {
		if(tunnelserver)
			return true;

		if(!to->status.reachable) {
			logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
				"ANS_KEY", c->name, c->hostname, to_name);
			return true;
		}

		if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
			char *address, *port;
			ifdebug(PROTOCOL) logger(LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
			sockaddr2str(&from->address, &address, &port);
			send_request(to->nexthop->connection, "%s %s %s", c->buffer, address, port);
			free(address);
			free(port);
			return true;
		}

		return send_request(to->nexthop->connection, "%s", c->buffer);
	}

	/* Update our copy of the origin's packet key */
	from->outkey = xrealloc(from->outkey, strlen(key) / 2);
	from->outkeylength = strlen(key) / 2;
	hex2bin(key, from->outkey, from->outkeylength);

	/* Check and lookup cipher and digest algorithms */

	if(cipher) {
		from->outcipher = EVP_get_cipherbynid(cipher);

		if(!from->outcipher) {
			logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name,
				   from->hostname);
			return true;
		}

		if(from->outkeylength != from->outcipher->key_len + from->outcipher->iv_len) {
			logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name,
				   from->hostname);
			return true;
		}
	} else {
		from->outcipher = NULL;
	}

	from->outmaclength = maclength;

	if(digest) {
		from->outdigest = EVP_get_digestbynid(digest);

		if(!from->outdigest) {
			logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name,
				   from->hostname);
			return true;
		}

		if(from->outmaclength > from->outdigest->md_size || from->outmaclength < 0) {
			logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!",
				   from->name, from->hostname);
			return true;
		}
	} else {
		from->outdigest = NULL;
	}

	if(compression < 0 || compression > 11) {
		logger(LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
		return true;
	}
	
	from->outcompression = compression;

	if(from->outcipher)
		if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) {
			logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s",
					from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
			return true;
		}

	from->status.validkey = true;
	from->sent_seqno = 0;

	if(*address && *port) {
		ifdebug(PROTOCOL) logger(LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
		sockaddr_t sa = str2sockaddr(address, port);
		update_node_udp(from, &sa);
	}

	if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuevent)
		send_mtu_probe(from);

	return true;
}
Пример #2
0
static void sssp_bfs(void) {
	avl_node_t *node, *next, *to;
	edge_t *e;
	node_t *n;
	list_t *todo_list;
	list_node_t *from, *todonext;
	bool indirect;
	char *name;
	char *address, *port;
	char *envp[7];
	int i;

	todo_list = list_alloc(NULL);

	/* Clear visited status on nodes */

	for(node = node_tree->head; node; node = node->next) {
		n = node->data;
		n->status.visited = false;
		n->status.indirect = true;
	}

	/* Begin with myself */

	myself->status.visited = true;
	myself->status.indirect = false;
	myself->nexthop = myself;
	myself->prevedge = NULL;
	myself->via = myself;
	list_insert_head(todo_list, myself);

	/* Loop while todo_list is filled */

	for(from = todo_list->head; from; from = todonext) {	/* "from" is the node from which we start */
		n = from->data;

		for(to = n->edge_tree->head; to; to = to->next) {	/* "to" is the edge connected to "from" */
			e = to->data;

			if(!e->reverse)
				continue;

			/* Situation:

				   /
				  /
			   ----->(n)---e-->(e->to)
				  \
				   \

			   Where e is an edge, (n) and (e->to) are nodes.
			   n->address is set to the e->address of the edge left of n to n.
			   We are currently examining the edge e right of n from n:

			   - If edge e provides for better reachability of e->to, update
			     e->to and (re)add it to the todo_list to (re)examine the reachability
			     of nodes behind it.
			 */

			indirect = n->status.indirect || e->options & OPTION_INDIRECT;

			if(e->to->status.visited
			   && (!e->to->status.indirect || indirect))
				continue;

			e->to->status.visited = true;
			e->to->status.indirect = indirect;
			e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
			e->to->prevedge = e;
			e->to->via = indirect ? n->via : e->to;
			e->to->options = e->options;

			if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
				update_node_udp(e->to, &e->address);

			list_insert_tail(todo_list, e->to);
		}

		todonext = from->next;
		list_delete_node(todo_list, from);
	}

	list_free(todo_list);

	/* Check reachability status. */

	for(node = node_tree->head; node; node = next) {
		next = node->next;
		n = node->data;

		if(n->status.visited != n->status.reachable) {
			n->status.reachable = !n->status.reachable;

			if(n->status.reachable) {
				ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
					   n->name, n->hostname);
			} else {
				ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
					   n->name, n->hostname);
			}

			/* TODO: only clear status.validkey if node is unreachable? */

			n->status.validkey = false;
			n->last_req_key = 0;

			n->maxmtu = MTU;
			n->minmtu = 0;
			n->mtuprobes = 0;

			if(n->mtuevent) {
				event_del(n->mtuevent);
				n->mtuevent = NULL;
			}

			xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
			xasprintf(&envp[1], "DEVICE=%s", device ? : "");
			xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
			xasprintf(&envp[3], "NODE=%s", n->name);
			sockaddr2str(&n->address, &address, &port);
			xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
			xasprintf(&envp[5], "REMOTEPORT=%s", port);
			envp[6] = NULL;

			execute_script(n->status.reachable ? "host-up" : "host-down", envp);

			xasprintf(&name,
					 n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
					 n->name);
			execute_script(name, envp);

			free(name);
			free(address);
			free(port);

			for(i = 0; i < 6; i++)
				free(envp[i]);

			subnet_update(n, NULL, n->status.reachable);

			if(!n->status.reachable)
				update_node_udp(n, NULL);
			else if(n->connection)
				send_ans_key(n);
		}
	}