Exemplo n.º 1
0
/*
  close all open network connections
*/
void close_network_connections(meshlink_handle_t *mesh) {
	if(mesh->connections) {
		for(list_node_t *node = mesh->connections->head, *next; node; node = next) {
			next = node->next;
			connection_t *c = node->data;
			c->outgoing = NULL;
			terminate_connection(mesh, c, false);
		}
	}

	if(mesh->outgoings)
		list_delete_list(mesh->outgoings);

	if(mesh->self && mesh->self->connection) {
		terminate_connection(mesh, mesh->self->connection, false);
		free_connection(mesh->self->connection);
	}

	for(int i = 0; i < mesh->listen_sockets; i++) {
		io_del(&mesh->loop, &mesh->listen_socket[i].tcp);
		io_del(&mesh->loop, &mesh->listen_socket[i].udp);
		close(mesh->listen_socket[i].tcp.fd);
		close(mesh->listen_socket[i].udp.fd);
	}

	exit_requests(mesh);
	exit_edges(mesh);
	exit_nodes(mesh);
	exit_connections(mesh);

	if(mesh->myport) free(mesh->myport);

	return;
}
Exemplo n.º 2
0
void exit_connections(meshlink_handle_t *mesh) {
	if(mesh->connections)
		list_delete_list(mesh->connections);

	free_connection(mesh->everyone);

	mesh->connections = NULL;
	mesh->everyone = NULL;
}
Exemplo n.º 3
0
/*
  close all open network connections
*/
void close_network_connections(void) {
    avl_node_t *node, *next;
    connection_t *c;
    char *envp[5];
    int i;

    for(node = connection_tree->head; node; node = next) {
        next = node->next;
        c = node->data;
        c->outgoing = NULL;
        terminate_connection(c, false);
    }

    for(list_node_t *node = outgoing_list->head; node; node = node->next) {
        outgoing_t *outgoing = node->data;

        if(outgoing->event)
            event_del(outgoing->event);
    }

    list_delete_list(outgoing_list);

    if(myself && myself->connection) {
        subnet_update(myself, NULL, false);
        terminate_connection(myself->connection, false);
        free_connection(myself->connection);
    }

    for(i = 0; i < listen_sockets; i++) {
        close(listen_socket[i].tcp);
        close(listen_socket[i].udp);
    }

    xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
    xasprintf(&envp[1], "DEVICE=%s", device ? : "");
    xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
    xasprintf(&envp[3], "NAME=%s", myself->name);
    envp[4] = NULL;

    exit_requests();
    exit_edges();
    exit_subnets();
    exit_nodes();
    exit_connections();
    exit_events();

    execute_script("tinc-down", envp);

    if(myport) free(myport);

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

    close_device();

    return;
}
Exemplo n.º 4
0
Arquivo: net.c Projeto: 95ulisse/tinc
/*
  this is where it all happens...
*/
int main_loop(void) {
	fd_set readset, writeset;
#ifdef HAVE_PSELECT
	struct timespec tv;
	sigset_t omask, block_mask;
	time_t next_event;
#else
	struct timeval tv;
#endif
	int r, maxfd;
	time_t last_ping_check, last_config_check, last_graph_dump;
	event_t *event;

	last_ping_check = now;
	last_config_check = now;
	last_graph_dump = now;
	
	srand(now);

#ifdef HAVE_PSELECT
	if(lookup_config(config_tree, "GraphDumpFile"))
		graph_dump = true;
	/* Block SIGHUP & SIGALRM */
	sigemptyset(&block_mask);
	sigaddset(&block_mask, SIGHUP);
	sigaddset(&block_mask, SIGALRM);
	sigprocmask(SIG_BLOCK, &block_mask, &omask);
#endif

	running = true;

	while(running) {
#ifdef HAVE_PSELECT
		next_event = last_ping_check + pingtimeout;
		if(graph_dump && next_event > last_graph_dump + 60)
			next_event = last_graph_dump + 60;

		if((event = peek_next_event()) && next_event > event->time)
			next_event = event->time;

		if(next_event <= now)
			tv.tv_sec = 0;
		else
			tv.tv_sec = next_event - now;
		tv.tv_nsec = 0;
#else
		tv.tv_sec = 1;
		tv.tv_usec = 0;
#endif

		maxfd = build_fdset(&readset, &writeset);

#ifdef HAVE_MINGW
		LeaveCriticalSection(&mutex);
#endif
#ifdef HAVE_PSELECT
		r = pselect(maxfd + 1, &readset, &writeset, NULL, &tv, &omask);
#else
		r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
#endif
		now = time(NULL);
#ifdef HAVE_MINGW
		EnterCriticalSection(&mutex);
#endif

		if(r < 0) {
			if(!sockwouldblock(sockerrno)) {
				logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
				dump_connections();
				return 1;
			}
		}

		if(r > 0)
			check_network_activity(&readset, &writeset);

		if(do_purge) {
			purge();
			do_purge = false;
		}

		/* Let's check if everybody is still alive */

		if(last_ping_check + pingtimeout <= now) {
			check_dead_connections();
			last_ping_check = now;

			if(routing_mode == RMODE_SWITCH)
				age_subnets();

			age_past_requests();

			/* Should we regenerate our key? */

			if(keyexpires <= now) {
				avl_node_t *node;
				node_t *n;

				ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");

				for(node = node_tree->head; node; node = node->next) {
					n = node->data;
					if(n->inkey) {
						free(n->inkey);
						n->inkey = NULL;
					}
				}

				send_key_changed();
				keyexpires = now + keylifetime;
			}

			/* Detect ADD_EDGE/DEL_EDGE storms that are caused when
			 * two tinc daemons with the same name are on the VPN.
			 * If so, sleep a while. If this happens multiple times
			 * in a row, sleep longer. */

			if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
				logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
				usleep(sleeptime * 1000000LL);
				sleeptime *= 2;
				if(sleeptime < 0)
					sleeptime = 3600;
			} else {
				sleeptime /= 2;
				if(sleeptime < 10)
					sleeptime = 10;
			}

			contradicting_add_edge = 0;
			contradicting_del_edge = 0;
		}

		if(sigalrm) {
			avl_node_t *node;
			logger(LOG_INFO, "Flushing event queue");
			expire_events();
			for(node = connection_tree->head; node; node = node->next) {
				connection_t *c = node->data;
				if(c->status.active)
					send_ping(c);
			}
			sigalrm = false;
		}

		while((event = get_expired_event())) {
			event->handler(event->data);
			free_event(event);
		}

		if(sighup) {
			connection_t *c;
			avl_node_t *node, *next;
			char *fname;
			struct stat s;
			
			sighup = false;

			reopenlogger();
			
			/* Reread our own configuration file */

			exit_configuration(&config_tree);
			init_configuration(&config_tree);

			if(!read_server_config()) {
				logger(LOG_ERR, "Unable to reread configuration file, exitting.");
				return 1;
			}

			/* Cancel non-active outgoing connections */

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

				c->outgoing = NULL;

				if(c->status.connecting) {
					terminate_connection(c, false);
					connection_del(c);
				}
			}

			/* Wipe list of outgoing connections */

			for(list_node_t *node = outgoing_list->head; node; node = node->next) {
				outgoing_t *outgoing = node->data;

				if(outgoing->event)
					event_del(outgoing->event);
			}

			list_delete_list(outgoing_list);

			/* Close connections to hosts that have a changed or deleted host config file */
			
			for(node = connection_tree->head; node; node = node->next) {
				c = node->data;
				
				xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
				if(stat(fname, &s) || s.st_mtime > last_config_check)
					terminate_connection(c, c->status.active);
				free(fname);
			}

			last_config_check = now;

			/* If StrictSubnet is set, expire deleted Subnets and read new ones in */

			if(strictsubnets) {
				subnet_t *subnet;

				for(node = subnet_tree->head; node; node = node->next) {
					subnet = node->data;
					subnet->expires = 1;
				}

				load_all_subnets();

				for(node = subnet_tree->head; node; node = next) {
					next = node->next;
					subnet = node->data;
					if(subnet->expires == 1) {
						send_del_subnet(everyone, subnet);
						if(subnet->owner->status.reachable)
							subnet_update(subnet->owner, subnet, false);
						subnet_del(subnet->owner, subnet);
					} else if(subnet->expires == -1) {
						subnet->expires = 0;
					} else {
						send_add_subnet(everyone, subnet);
						if(subnet->owner->status.reachable)
							subnet_update(subnet->owner, subnet, true);
					}
				}
			}

			/* Try to make outgoing connections */
			
			try_outgoing_connections();
		}
		
		/* Dump graph if wanted every 60 seconds*/

		if(last_graph_dump + 60 <= now) {
			dump_graph();
			last_graph_dump = now;
		}
	}

#ifdef HAVE_PSELECT
	/* Restore SIGHUP & SIGALARM mask */
	sigprocmask(SIG_SETMASK, &omask, NULL);
#endif

	return 0;
}
Exemplo n.º 5
0
Arquivo: tincd.c Projeto: seehuhn/tinc
int main2(int argc, char **argv) {
	InitializeCriticalSection(&mutex);
	EnterCriticalSection(&mutex);
#endif
	char *priority = NULL;

	if(!detach()) {
		return 1;
	}

#ifdef HAVE_MLOCKALL

	/* Lock all pages into memory if requested.
	 * This has to be done after daemon()/fork() so it works for child.
	 * No need to do that in parent as it's very short-lived. */
	if(do_mlock && mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
		logger(LOG_ERR, "System call `%s' failed: %s", "mlockall",
			   strerror(errno));
		return 1;
	}

#endif

	/* Setup sockets and open device. */

	if(!setup_network()) {
		goto end;
	}

	/* Initiate all outgoing connections. */

	try_outgoing_connections();

	/* Change process priority */

	if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) {
		if(!strcasecmp(priority, "Normal")) {
			if(setpriority(NORMAL_PRIORITY_CLASS) != 0) {
				logger(LOG_ERR, "System call `%s' failed: %s",
					   "setpriority", strerror(errno));
				goto end;
			}
		} else if(!strcasecmp(priority, "Low")) {
			if(setpriority(BELOW_NORMAL_PRIORITY_CLASS) != 0) {
				logger(LOG_ERR, "System call `%s' failed: %s",
					   "setpriority", strerror(errno));
				goto end;
			}
		} else if(!strcasecmp(priority, "High")) {
			if(setpriority(HIGH_PRIORITY_CLASS) != 0) {
				logger(LOG_ERR, "System call `%s' failed: %s",
					   "setpriority", strerror(errno));
				goto end;
			}
		} else {
			logger(LOG_ERR, "Invalid priority `%s`!", priority);
			goto end;
		}
	}

	/* drop privileges */
	if(!drop_privs()) {
		goto end;
	}

	/* Start main loop. It only exits when tinc is killed. */

	status = main_loop();

	/* Shutdown properly. */

	ifdebug(CONNECTIONS)
	devops.dump_stats();

	close_network_connections();

end:
	logger(LOG_NOTICE, "Terminating");

#ifndef HAVE_MINGW
	remove_pid(pidfilename);
#endif

	free(priority);

#if OPENSSL_VERSION_NUMBER < 0x10100000L
	EVP_cleanup();
	ERR_free_strings();
#ifndef OPENSSL_NO_ENGINE
	ENGINE_cleanup();
#endif
#endif

	exit_configuration(&config_tree);
	list_delete_list(cmdline_conf);
	free_names();

	return status;
}
Exemplo n.º 6
0
void exit_connections(void) {
	list_delete_list(connection_list);
	free_connection(everyone);
}