+/*
+ Configure connection_t myself and set up the local sockets (listen only)
+*/
+int setup_myself(void)
+{
+ config_t const *cfg;
+ config_t *next;
+ subnet_t *net;
+cp
+ myself = new_connection();
+
+ asprintf(&myself->hostname, _("MYSELF"));
+ myself->options = 0;
+ myself->protocol_version = PROT_CURRENT;
+
+ if(!(cfg = get_config_val(config, config_name))) /* Not acceptable */
+ {
+ syslog(LOG_ERR, _("Name for tinc daemon required!"));
+ return -1;
+ }
+ else
+ asprintf(&myself->name, "%s", (char*)cfg->data.val);
+
+ if(check_id(myself->name))
+ {
+ syslog(LOG_ERR, _("Invalid name for myself!"));
+ return -1;
+ }
+cp
+ if(read_rsa_private_key())
+ return -1;
+
+ if(read_host_config(myself))
+ {
+ syslog(LOG_ERR, _("Cannot open host configuration file for myself!"));
+ return -1;
+ }
+
+ if(read_rsa_public_key(myself))
+ return -1;
+cp
+
+/*
+ if(RSA_check_key(myself->rsa_key) != 1)
+ {
+ syslog(LOG_ERR, _("Invalid public/private keypair!"));
+ return -1;
+ }
+*/
+ if(!(cfg = get_config_val(myself->config, config_port)))
+ myself->port = 655;
+ else
+ myself->port = cfg->data.val;
+
+/* Read in all the subnets specified in the host configuration file */
+
+ for(next = myself->config; (cfg = get_config_val(next, config_subnet)); next = cfg->next)
+ {
+ net = new_subnet();
+ net->type = SUBNET_IPV4;
+ net->net.ipv4.address = cfg->data.ip->address;
+ net->net.ipv4.mask = cfg->data.ip->mask;
+
+ /* Teach newbies what subnets are... */
+
+ if((net->net.ipv4.address & net->net.ipv4.mask) != net->net.ipv4.address)
+ {
+ syslog(LOG_ERR, _("Network address and subnet mask do not match!"));
+ return -1;
+ }
+
+ subnet_add(myself, net);
+ }
+
+cp
+ /* Check some options */
+
+ if((cfg = get_config_val(config, config_indirectdata)))
+ if(cfg->data.val == stupid_true)
+ myself->options |= OPTION_INDIRECT;
+
+ if((cfg = get_config_val(config, config_tcponly)))
+ if(cfg->data.val == stupid_true)
+ myself->options |= OPTION_TCPONLY;
+
+ if((cfg = get_config_val(myself->config, config_indirectdata)))
+ if(cfg->data.val == stupid_true)
+ myself->options |= OPTION_INDIRECT;
+
+ if((cfg = get_config_val(myself->config, config_tcponly)))
+ if(cfg->data.val == stupid_true)
+ myself->options |= OPTION_TCPONLY;
+
+ if(myself->options & OPTION_TCPONLY)
+ myself->options |= OPTION_INDIRECT;
+
+ if((cfg = get_config_val(config, config_mode)))
+ {
+ if(!strcasecmp(cfg->data.ptr, "router"))
+ routing_mode = RMODE_ROUTER;
+ else if (!strcasecmp(cfg->data.ptr, "switch"))
+ routing_mode = RMODE_SWITCH;
+ else if (!strcasecmp(cfg->data.ptr, "hub"))
+ routing_mode = RMODE_HUB;
+ else
+ {
+ syslog(LOG_ERR, _("Invalid routing mode!"));
+ return -1;
+ }
+ }
+ else
+ routing_mode = RMODE_ROUTER;
+
+cp
+ /* Open sockets */
+
+ if((myself->meta_socket = setup_listen_meta_socket(myself->port)) < 0)
+ {
+ syslog(LOG_ERR, _("Unable to set up a listening TCP socket!"));
+ return -1;
+ }
+
+ if((myself->socket = setup_vpn_in_socket(myself->port)) < 0)
+ {
+ syslog(LOG_ERR, _("Unable to set up a listening UDP socket!"));
+ return -1;
+ }
+cp
+ /* Generate packet encryption key */
+
+ myself->cipher_pkttype = EVP_bf_cbc();
+
+ myself->cipher_pktkeylength = myself->cipher_pkttype->key_len + myself->cipher_pkttype->iv_len;
+
+ myself->cipher_pktkey = (char *)xmalloc(myself->cipher_pktkeylength);
+ RAND_pseudo_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength);
+
+ if(!(cfg = get_config_val(config, config_keyexpire)))
+ keylifetime = 3600;
+ else
+ keylifetime = cfg->data.val;
+
+ keyexpires = time(NULL) + keylifetime;
+cp
+
+ /* Activate ourselves */
+
+ myself->status.active = 1;
+
+ syslog(LOG_NOTICE, _("Ready: listening on port %hd"), myself->port);
+cp
+ return 0;
+}
+
+RETSIGTYPE
+sigalrm_handler(int a)
+{
+ config_t const *cfg;
+cp
+ cfg = get_config_val(upstreamcfg, config_connectto);
+
+ if(!cfg)
+ {
+ if(upstreamcfg == config)
+ {
+ /* No upstream IP given, we're listen only. */
+ signal(SIGALRM, SIG_IGN);
+ return;
+ }
+ }
+ else
+ {
+ /* We previously tried all the ConnectTo lines. Now wrap back to the first. */
+ cfg = get_config_val(config, config_connectto);
+ }
+
+ while(cfg)
+ {
+ upstreamcfg = cfg->next;
+ if(!setup_outgoing_connection(cfg->data.ptr)) /* function returns 0 when there are no problems */
+ {
+ signal(SIGALRM, SIG_IGN);
+ return;
+ }
+ cfg = get_config_val(upstreamcfg, config_connectto); /* Or else we try the next ConnectTo line */
+ }
+
+ signal(SIGALRM, sigalrm_handler);
+ upstreamcfg = config;
+ seconds_till_retry += 5;
+ if(seconds_till_retry > MAXTIMEOUT) /* Don't wait more than MAXTIMEOUT seconds. */
+ seconds_till_retry = MAXTIMEOUT;
+ syslog(LOG_ERR, _("Still failed to connect to other, will retry in %d seconds"),
+ seconds_till_retry);
+ alarm(seconds_till_retry);
+cp
+}
+
+/*
+ setup all initial network connections
+*/
+int setup_network_connections(void)
+{
+ config_t const *cfg;
+cp
+ init_connections();
+ init_subnets();
+
+ if((cfg = get_config_val(config, config_pingtimeout)) == NULL)
+ timeout = 60;
+ else
+ {
+ timeout = cfg->data.val;
+ if(timeout < 1)
+ {
+ timeout = 86400;
+ }
+ }
+
+ if(setup_tap_fd() < 0)
+ return -1;
+
+ /* Run tinc-up script to further initialize the tap interface */
+ execute_script("tinc-up");
+
+ if(setup_myself() < 0)
+ return -1;
+
+ if(!(cfg = get_config_val(config, config_connectto)))
+ /* No upstream IP given, we're listen only. */
+ return 0;
+
+ while(cfg)
+ {
+ upstreamcfg = cfg->next;
+ if(!setup_outgoing_connection(cfg->data.ptr)) /* function returns 0 when there are no problems */
+ return 0;
+ cfg = get_config_val(upstreamcfg, config_connectto); /* Or else we try the next ConnectTo line */
+ }
+
+ if(do_detach)
+ {
+ signal(SIGALRM, sigalrm_handler);
+ upstreamcfg = config;
+ seconds_till_retry = MAXTIMEOUT;
+ syslog(LOG_NOTICE, _("Trying to re-establish outgoing connection in %d seconds"), seconds_till_retry);
+ alarm(seconds_till_retry);
+ }
+ else
+ return -1;
+
+cp
+ return 0;
+}
+
+/*
+ close all open network connections
+*/
+void close_network_connections(void)
+{
+ avl_node_t *node;
+ connection_t *p;
+cp
+ for(node = connection_tree->head; node; node = node->next)
+ {
+ p = (connection_t *)node->data;
+ p->status.outgoing = 0;
+ p->status.active = 0;
+ terminate_connection(p);
+ }
+
+ if(myself)
+ if(myself->status.active)
+ {
+ close(myself->meta_socket);
+ free_connection(myself);
+ myself = NULL;
+ }
+
+ close(tap_fd);
+
+ /* Execute tinc-down script right after shutting down the interface */
+ execute_script("tinc-down");
+
+ destroy_connection_tree();
+cp
+ return;
+}
+