Exemple #1
0
/*
  Terminate a connection:
  - Close the socket
  - Remove associated edge and tell other connections about it if report = true
  - Check if we need to retry making an outgoing connection
  - Deactivate the host
*/
void terminate_connection(connection_t *c, bool report) {
	if(c->status.remove)
		return;

	ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
			   c->name, c->hostname);

	c->status.remove = true;
	c->status.active = false;

	if(c->node)
		c->node->connection = NULL;

	if(c->socket)
		closesocket(c->socket);

	if(c->edge) {
		if(!c->node) {
			logger(LOG_ERR, "Connection to %s (%s) has an edge but node is NULL!", c->name, c->hostname);
			// And that should never happen.
			abort();
		}

		if(report && !tunnelserver)
			send_del_edge(everyone, c->edge);

		edge_del(c->edge);

		/* Run MST and SSSP algorithms */

		graph();

		/* If the node is not reachable anymore but we remember it had an edge to us, clean it up */

		if(report && !c->node->status.reachable) {
			edge_t *e;
			e = lookup_edge(c->node, myself);
			if(e) {
				if(!tunnelserver)
					send_del_edge(everyone, e);
				edge_del(e);
			}
		}
	}

	free_connection_partially(c);

	/* Check if this was our outgoing connection */

	if(c->outgoing) {
		c->status.remove = false;
		do_outgoing_connection(c);	
	}

#ifndef HAVE_MINGW
	/* Clean up dead proxy processes */

	while(waitpid(-1, NULL, WNOHANG) > 0);
#endif
}
Exemple #2
0
/*
  Check if the other end is active.
  If we have sent packets, but didn't receive any,
  then possibly the other end is dead. We send a
  PING request over the meta connection. If the other
  end does not reply in time, we consider them dead
  and close the connection.
*/
static void check_dead_connections(void) {
	avl_node_t *node, *next;
	connection_t *c;

	for(node = connection_tree->head; node; node = next) {
		next = node->next;
		c = node->data;

		if(c->last_ping_time + pingtimeout <= now) {
			if(c->status.active) {
				if(c->status.pinged) {
					ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
							   c->name, c->hostname, (long)now - c->last_ping_time);
					c->status.timeout = true;
					terminate_connection(c, true);
				} else if(c->last_ping_time + pinginterval <= now) {
					send_ping(c);
				}
			} else {
				if(c->status.remove) {
					logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...",
						   c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status));
					connection_del(c);
					continue;
				}
				ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication",
						   c->name, c->hostname);
				if(c->status.connecting) {
					c->status.connecting = false;
					closesocket(c->socket);
					do_outgoing_connection(c);
				} else {
					terminate_connection(c, false);
				}
			}
		}

		if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout <= now) {
			if(c->status.active) {
				ifdebug(CONNECTIONS) logger(LOG_INFO,
						"%s (%s) could not flush for %ld seconds (%d bytes remaining)",
						c->name, c->hostname, (long)now - c->last_flushed_time, c->outbuflen);
				c->status.timeout = true;
				terminate_connection(c, true);
			}
		}
	}
}
Exemple #3
0
void setup_outgoing_connection(outgoing_t *outgoing) {
	connection_t *c;
	node_t *n;

	outgoing->event = NULL;

	n = lookup_node(outgoing->name);

	if(n)
		if(n->connection) {
			ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name);

			n->connection->outgoing = outgoing;
			return;
		}

	c = new_connection();
	c->name = xstrdup(outgoing->name);
	c->outcipher = myself->connection->outcipher;
	c->outdigest = myself->connection->outdigest;
	c->outmaclength = myself->connection->outmaclength;
	c->outcompression = myself->connection->outcompression;

	init_configuration(&c->config_tree);
	read_connection_config(c);

	outgoing->cfg = lookup_config(c->config_tree, "Address");

	if(!outgoing->cfg) {
		logger(LOG_ERR, "No address specified for %s", c->name);
		free_connection(c);
		return;
	}

	c->outgoing = outgoing;
	c->last_ping_time = now;

	connection_add(c);

	do_outgoing_connection(c);
}
Exemple #4
0
/*
  check all connections to see if anything
  happened on their sockets
*/
static void check_network_activity(fd_set * readset, fd_set * writeset) {
	connection_t *c;
	avl_node_t *node;
	int result, i;
	socklen_t len = sizeof(result);
	vpn_packet_t packet;
	static int errors = 0;

	/* check input from kernel */
	if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
		if(devops.read(&packet)) {
			if(packet.len) {
				errors = 0;
				packet.priority = 0;
				route(myself, &packet);
			}
		} else {
			usleep(errors * 50000);
			errors++;
			if(errors > 10) {
				logger(LOG_ERR, "Too many errors from %s, exiting!", device);
				running = false;
			}
		}
	}

	/* check meta connections */
	for(node = connection_tree->head; node; node = node->next) {
		c = node->data;

		if(c->status.remove)
			continue;

		if(FD_ISSET(c->socket, writeset)) {
			if(c->status.connecting) {
				c->status.connecting = false;
				getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);

				if(!result)
					finish_connecting(c);
				else {
					ifdebug(CONNECTIONS) logger(LOG_DEBUG,
							   "Error while connecting to %s (%s): %s",
							   c->name, c->hostname, sockstrerror(result));
					closesocket(c->socket);
					do_outgoing_connection(c);
					continue;
				}
			}

			if(!flush_meta(c)) {
				terminate_connection(c, c->status.active);
				continue;
			}
		}

		if(FD_ISSET(c->socket, readset)) {
			if(!receive_meta(c)) {
				terminate_connection(c, c->status.active);
				continue;
			}
		}
	}

	for(i = 0; i < listen_sockets; i++) {
		if(FD_ISSET(listen_socket[i].udp, readset))
			handle_incoming_vpn_data(i);

		if(FD_ISSET(listen_socket[i].tcp, readset))
			handle_new_meta_connection(listen_socket[i].tcp);
	}
}