Example #1
0
static boolean_t
sfunc_addr_address(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
{
	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
	ipmp_addrinfo_t *adinfop = arg->sa_data;

	sockaddr2str(&adinfop->ad_addr, buf, bufsize);
	return (B_TRUE);
}
Example #2
0
static boolean_t
sfunc_targ_testaddr(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
{
	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
	ipmp_targinfo_t *targinfop = arg->sa_data;

	if (targinfop->it_targmode != IPMP_TARG_DISABLED)
		sockaddr2str(&targinfop->it_testaddr, buf, bufsize);
	return (B_TRUE);
}
Example #3
0
bool send_add_edge(connection_t *c, const edge_t *e) {
	bool x;
	char *address, *port;

	sockaddr2str(&e->address, &address, &port);

	x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(),
					 e->from->name, e->to->name, address, port,
					 e->options, e->weight);
	free(address);
	free(port);

	return x;
}
Example #4
0
static boolean_t
sfunc_probe_target(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
{
	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
	uint_t nelem;
	struct sockaddr_storage *target;
	nvlist_t *nvl = arg->sa_data;

	if (nvlist_lookup_byte_array(nvl, IPMP_PROBE_TARGET,
	    (uchar_t **)&target, &nelem) != 0)
		return (sfunc_nvwarn("IPMP_PROBE_TARGET"));

	sockaddr2str(target, buf, bufsize);
	return (B_TRUE);
}
Example #5
0
static void do_outgoing_pipe(connection_t *c, char *command) {
#ifndef HAVE_MINGW
	int fd[2];

	if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
		logger(LOG_ERR, "Could not create socketpair: %s\n", strerror(errno));
		return;
	}

	if(fork()) {
		c->socket = fd[0];
		close(fd[1]);
		ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Using proxy %s", command);
		return;
	}

	close(0);
	close(1);
	close(fd[0]);
	dup2(fd[1], 0);
	dup2(fd[1], 1);
	close(fd[1]);

	// Other filedescriptors should be closed automatically by CLOEXEC

	char *host = NULL;
	char *port = NULL;

	sockaddr2str(&c->address, &host, &port);
	setenv("REMOTEADDRESS", host, true);
	setenv("REMOTEPORT", port, true);
	setenv("NODE", c->name, true);
	setenv("NAME", myself->name, true);
	if(netname)
		setenv("NETNAME", netname, true);

	int result = system(command);
	if(result < 0)
		logger(LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno));
	else if(result)
		logger(LOG_ERR, "%s exited with non-zero status %d", command, result);
	exit(result);
#else
	logger(LOG_ERR, "Proxy type exec not supported on this platform!");
	return;
#endif
}
Example #6
0
static boolean_t
sfunc_targ_targets(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
{
	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
	uint_t i;
	char *targname = alloca(bufsize);
	ipmp_targinfo_t *targinfop = arg->sa_data;
	ipmp_addrlist_t *targlistp = targinfop->it_targlistp;

	for (i = 0; i < targlistp->al_naddr; i++) {
		sockaddr2str(&targlistp->al_addrs[i], targname, bufsize);
		(void) strlcat(buf, targname, bufsize);
		if ((i + 1) < targlistp->al_naddr)
			(void) strlcat(buf, " ", bufsize);
	}
	return (B_TRUE);
}
Example #7
0
static bool finalize_invitation(connection_t *c, const char *data, uint16_t len) {
	if(strchr(data, '\n')) {
		logger(DEBUG_ALWAYS, LOG_ERR, "Received invalid key from invited node %s (%s)!\n", c->name, c->hostname);
		return false;
	}

	// Create a new host config file
	char filename[PATH_MAX];
	snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
	if(!access(filename, F_OK)) {
		logger(DEBUG_ALWAYS, LOG_ERR, "Host config file for %s (%s) already exists!\n", c->name, c->hostname);
		return false;
	}

	FILE *f = fopen(filename, "w");
	if(!f) {
		logger(DEBUG_ALWAYS, LOG_ERR, "Error trying to create %s: %s\n", filename, strerror(errno));
		return false;
	}

	fprintf(f, "Ed25519PublicKey = %s\n", data);
	fclose(f);

	logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname);

	// Call invitation-accepted script
	char *envp[7] = {NULL};
	char *address, *port;

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

	execute_script("invitation-accepted", envp);

	for(int i = 0; envp[i] && i < 7; i++)
		free(envp[i]);

	sptps_send_record(&c->sptps, 2, data, 0);
	return true;
}
Example #8
0
/*
 * Nested walker callback function for walk_addr().
 */
static void
walk_addr_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
{
	int err;
	uint_t i;
	ipmp_groupinfo_t *grinfop = infop;
	ipmp_addrinfo_t *adinfop;
	ipmp_addrlist_t *adlistp = grinfop->gr_adlistp;
	ipmpstat_walkdata_t *iwp = arg;
	char addr[INET6_ADDRSTRLEN];
	struct sockaddr_storage *addrp;

	for (i = 0; i < adlistp->al_naddr; i++) {
		addrp = &adlistp->al_addrs[i];
		err = ipmp_getaddrinfo(ih, grinfop->gr_name, addrp, &adinfop);
		if (err != IPMP_SUCCESS) {
			sockaddr2str(addrp, addr, sizeof (addr));
			warn_ipmperr(err, "cannot get info for `%s'", addr);
			continue;
		}
		(*iwp->iw_func)(ih, adinfop, iwp->iw_funcarg);
		ipmp_freeaddrinfo(adinfop);
	}
}
Example #9
0
int cmd_join(int argc, char *argv[]) {
	free(data);
	data = NULL;
	datalen = 0;

	if(argc > 2) {
		fprintf(stderr, "Too many arguments!\n");
		return 1;
	}

	// Make sure confbase exists and is accessible.
	if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
		fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
		return 1;
	}

	if(mkdir(confbase, 0777) && errno != EEXIST) {
		fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
		return 1;
	}

	if(access(confbase, R_OK | W_OK | X_OK)) {
		fprintf(stderr, "No permission to write in directory %s: %s\n", confbase, strerror(errno));
		return 1;
	}

	// If a netname or explicit configuration directory is specified, check for an existing tinc.conf.
	if((netname || confbasegiven) && !access(tinc_conf, F_OK)) {
		fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
		return 1;
	}

	// Either read the invitation from the command line or from stdin.
	char *invitation;

	if(argc > 1) {
		invitation = argv[1];
	} else {
		if(tty)
			fprintf(stderr, "Enter invitation URL: ");
		errno = EPIPE;
		if(!fgets(line, sizeof line, stdin)) {
			fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
			return false;
		}
		invitation = line;
	}

	// Parse the invitation URL.
	rstrip(line);

	char *slash = strchr(invitation, '/');
	if(!slash)
		goto invalid;

	*slash++ = 0;

	if(strlen(slash) != 48)
		goto invalid;

	char *address = invitation;
	char *port = NULL;
	if(*address == '[') {
		address++;
		char *bracket = strchr(address, ']');
		if(!bracket)
			goto invalid;
		*bracket = 0;
		if(bracket[1] == ':')
			port = bracket + 2;
	} else {
		port = strchr(address, ':');
		if(port)
			*port++ = 0;
	}

	if(!port || !*port)
		port = "655";

	if(!b64decode(slash, hash, 24) || !b64decode(slash + 24, cookie, 24))
		goto invalid;

	// Generate a throw-away key for the invitation.
	ecdsa_t *key = ecdsa_generate();
	if(!key)
		return 1;

	char *b64key = ecdsa_get_base64_public_key(key);

	// Connect to the tinc daemon mentioned in the URL.
	struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
	if(!ai)
		return 1;

	struct addrinfo *aip = NULL;

next:
	if(!aip)
		aip = ai;
	else {
		aip = aip->ai_next;
		if(!aip)
			return 1;
	}

	sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
	if(sock <= 0) {
		fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
		goto next;
	}

	if(connect(sock, aip->ai_addr, aip->ai_addrlen)) {
		char *addrstr, *portstr;
		sockaddr2str((sockaddr_t *)aip->ai_addr, &addrstr, &portstr);
		fprintf(stderr, "Could not connect to %s port %s: %s\n", addrstr, portstr, strerror(errno));
		free(addrstr);
		free(portstr);
		closesocket(sock);
		goto next;
	}

	fprintf(stderr, "Connected to %s port %s...\n", address, port);

	// Tell him we have an invitation, and give him our throw-away key.
	int len = snprintf(line, sizeof line, "0 ?%s %d.%d\n", b64key, PROT_MAJOR, PROT_MINOR);
	if(len <= 0 || len >= sizeof line)
		abort();

	if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) {
		fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
		closesocket(sock);
		goto next;
	}

	char hisname[4096] = "";
	int code, hismajor, hisminor = 0;

	if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) {
		fprintf(stderr, "Cannot read greeting from peer\n");
		closesocket(sock);
		goto next;
	}

	// Check if the hash of the key he gave us matches the hash in the URL.
	char *fingerprint = line + 2;
	char hishash[64];
	if(sha512(fingerprint, strlen(fingerprint), hishash)) {
		fprintf(stderr, "Could not create digest\n%s\n", line + 2);
		return 1;
	}
	if(memcmp(hishash, hash, 18)) {
		fprintf(stderr, "Peer has an invalid key!\n%s\n", line + 2);
		return 1;

	}
	
	ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint);
	if(!hiskey)
		return 1;

	// Start an SPTPS session
	if(!sptps_start(&sptps, NULL, true, false, key, hiskey, "tinc invitation", 15, invitation_send, invitation_receive))
		return 1;

	// Feed rest of input buffer to SPTPS
	if(!sptps_receive_data(&sptps, buffer, blen))
		return 1;

	while((len = recv(sock, line, sizeof line, 0))) {
		if(len < 0) {
			if(errno == EINTR)
				continue;
			fprintf(stderr, "Error reading data from %s port %s: %s\n", address, port, strerror(errno));
			return 1;
		}

		char *p = line;
		while(len) {
			int done = sptps_receive_data(&sptps, p, len);
			if(!done)
				return 1;
			len -= done;
			p += done;
		}
	}
	
	sptps_stop(&sptps);
	ecdsa_free(hiskey);
	ecdsa_free(key);
	closesocket(sock);

	if(!success) {
		fprintf(stderr, "Connection closed by peer, invitation cancelled.\n");
		return 1;
	}

	return 0;

invalid:
	fprintf(stderr, "Invalid invitation URL.\n");
	return 1;
}
Example #10
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);
		}
	}
Example #11
0
/*
  Configure node_t myself and set up the local sockets (listen only)
*/
bool setup_myself(void) {
    config_t *cfg;
    subnet_t *subnet;
    char *name, *hostname, *mode, *afname, *cipher, *digest;
    char *fname = NULL;
    char *address = NULL;
    char *envp[5];
    struct addrinfo *ai, *aip, hint = {0};
    bool choice;
    int i, err;
    int replaywin_int;

    myself = new_node();
    myself->connection = new_connection();

    myself->hostname = xstrdup("MYSELF");
    myself->connection->hostname = xstrdup("MYSELF");

    myself->connection->options = 0;
    myself->connection->protocol_version = PROT_CURRENT;

    if(!get_config_string(lookup_config(config_tree, "Name"), &name)) {	/* Not acceptable */
        logger(LOG_ERR, "Name for tinc daemon required!");
        return false;
    }

    if(!check_id(name)) {
        logger(LOG_ERR, "Invalid name for myself!");
        free(name);
        return false;
    }

    myself->name = name;
    myself->connection->name = xstrdup(name);
    xasprintf(&fname, "%s/hosts/%s", confbase, name);
    read_config_options(config_tree, name);
    read_config_file(config_tree, fname);
    free(fname);

    if(!read_rsa_private_key())
        return false;

    if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
        myport = xstrdup("655");

    if(!atoi(myport)) {
        struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
        sockaddr_t sa;
        if(!ai || !ai->ai_addr)
            return false;
        free(myport);
        memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
        sockaddr2str(&sa, NULL, &myport);
    }

    /* Read in all the subnets specified in the host configuration file */

    cfg = lookup_config(config_tree, "Subnet");

    while(cfg) {
        if(!get_config_subnet(cfg, &subnet))
            return false;

        subnet_add(myself, subnet);

        cfg = lookup_config_next(config_tree, cfg);
    }

    /* Check some options */

    if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
        myself->options |= OPTION_INDIRECT;

    if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice)
        myself->options |= OPTION_TCPONLY;

    if(myself->options & OPTION_TCPONLY)
        myself->options |= OPTION_INDIRECT;

    get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
    get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
    get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
    strictsubnets |= tunnelserver;

    if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
        if(!strcasecmp(mode, "router"))
            routing_mode = RMODE_ROUTER;
        else if(!strcasecmp(mode, "switch"))
            routing_mode = RMODE_SWITCH;
        else if(!strcasecmp(mode, "hub"))
            routing_mode = RMODE_HUB;
        else {
            logger(LOG_ERR, "Invalid routing mode!");
            return false;
        }
        free(mode);
    }

    if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
        if(!strcasecmp(mode, "off"))
            forwarding_mode = FMODE_OFF;
        else if(!strcasecmp(mode, "internal"))
            forwarding_mode = FMODE_INTERNAL;
        else if(!strcasecmp(mode, "kernel"))
            forwarding_mode = FMODE_KERNEL;
        else {
            logger(LOG_ERR, "Invalid forwarding mode!");
            return false;
        }
        free(mode);
    }

    choice = true;
    get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice);
    if(choice)
        myself->options |= OPTION_PMTU_DISCOVERY;

    choice = true;
    get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice);
    if(choice)
        myself->options |= OPTION_CLAMP_MSS;

    get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);

#if !defined(SOL_IP) || !defined(IP_TOS)
    if(priorityinheritance)
        logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
#endif

    if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
        macexpire = 600;

    if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
        if(maxtimeout <= 0) {
            logger(LOG_ERR, "Bogus maximum timeout!");
            return false;
        }
    } else
        maxtimeout = 900;

    if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
        if(udp_rcvbuf <= 0) {
            logger(LOG_ERR, "UDPRcvBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
        if(udp_sndbuf <= 0) {
            logger(LOG_ERR, "UDPSndBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
        if(replaywin_int < 0) {
            logger(LOG_ERR, "ReplayWindow cannot be negative!");
            return false;
        }
        replaywin = (unsigned)replaywin_int;
    }

    if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
        if(!strcasecmp(afname, "IPv4"))
            addressfamily = AF_INET;
        else if(!strcasecmp(afname, "IPv6"))
            addressfamily = AF_INET6;
        else if(!strcasecmp(afname, "any"))
            addressfamily = AF_UNSPEC;
        else {
            logger(LOG_ERR, "Invalid address family!");
            return false;
        }
        free(afname);
    }

    get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);

    /* Generate packet encryption key */

    if(get_config_string
            (lookup_config(config_tree, "Cipher"), &cipher)) {
        if(!strcasecmp(cipher, "none")) {
            myself->incipher = NULL;
        } else {
            myself->incipher = EVP_get_cipherbyname(cipher);

            if(!myself->incipher) {
                logger(LOG_ERR, "Unrecognized cipher type!");
                return false;
            }
        }
    } else
        myself->incipher = EVP_bf_cbc();

    if(myself->incipher)
        myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
    else
        myself->inkeylength = 1;

    myself->connection->outcipher = EVP_bf_ofb();

    if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
        keylifetime = 3600;

    keyexpires = now + keylifetime;

    /* Check if we want to use message authentication codes... */

    if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) {
        if(!strcasecmp(digest, "none")) {
            myself->indigest = NULL;
        } else {
            myself->indigest = EVP_get_digestbyname(digest);

            if(!myself->indigest) {
                logger(LOG_ERR, "Unrecognized digest type!");
                return false;
            }
        }
    } else
        myself->indigest = EVP_sha1();

    myself->connection->outdigest = EVP_sha1();

    if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) {
        if(myself->indigest) {
            if(myself->inmaclength > myself->indigest->md_size) {
                logger(LOG_ERR, "MAC length exceeds size of digest!");
                return false;
            } else if(myself->inmaclength < 0) {
                logger(LOG_ERR, "Bogus MAC length!");
                return false;
            }
        }
    } else
        myself->inmaclength = 4;

    myself->connection->outmaclength = 0;

    /* Compression */

    if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
        if(myself->incompression < 0 || myself->incompression > 11) {
            logger(LOG_ERR, "Bogus compression level!");
            return false;
        }
    } else
        myself->incompression = 0;

    myself->connection->outcompression = 0;

    /* Done */

    myself->nexthop = myself;
    myself->via = myself;
    myself->status.reachable = true;
    node_add(myself);

    graph();

    if(strictsubnets)
        load_all_subnets();

    /* Open device */

    if(!setup_device())
        return false;

    /* Run tinc-up script to further initialize the tap interface */
    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;

    execute_script("tinc-up", envp);

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

    /* Run subnet-up scripts for our own subnets */

    subnet_update(myself, NULL, true);

    /* Open sockets */

    get_config_string(lookup_config(config_tree, "BindToAddress"), &address);

    hint.ai_family = addressfamily;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_protocol = IPPROTO_TCP;
    hint.ai_flags = AI_PASSIVE;

    err = getaddrinfo(address, myport, &hint, &ai);

    if(err || !ai) {
        logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
               gai_strerror(err));
        return false;
    }

    listen_sockets = 0;

    for(aip = ai; aip; aip = aip->ai_next) {
        listen_socket[listen_sockets].tcp =
            setup_listen_socket((sockaddr_t *) aip->ai_addr);

        if(listen_socket[listen_sockets].tcp < 0)
            continue;

        listen_socket[listen_sockets].udp =
            setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);

        if(listen_socket[listen_sockets].udp < 0)
            continue;

        ifdebug(CONNECTIONS) {
            hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
            logger(LOG_NOTICE, "Listening on %s", hostname);
            free(hostname);
        }

        memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
        listen_sockets++;
    }

    freeaddrinfo(ai);

    if(listen_sockets)
        logger(LOG_NOTICE, "Ready");
    else {
        logger(LOG_ERR, "Unable to create any listening socket!");
        return false;
    }

    return true;
}
Example #12
0
/*
  Configure node_t myself and set up the local sockets (listen only)
*/
static bool setup_myself(void) {
    config_t *cfg;
    subnet_t *subnet;
    char *name, *hostname, *mode, *afname, *cipher, *digest, *type;
    char *fname = NULL;
    char *address = NULL;
    char *proxy = NULL;
    char *space;
    char *envp[5] = {NULL};
    struct addrinfo *ai, *aip, hint = {0};
    bool choice;
    int i, err;
    int replaywin_int;
    bool port_specified = false;

    myself = new_node();
    myself->connection = new_connection();

    myself->hostname = xstrdup("MYSELF");
    myself->connection->hostname = xstrdup("MYSELF");

    myself->connection->options = 0;
    myself->connection->protocol_version = PROT_CURRENT;

    if(!(name = get_name())) {
        logger(LOG_ERR, "Name for tinc daemon required!");
        return false;
    }

    /* Read tinc.conf and our own host config file */

    myself->name = name;
    myself->connection->name = xstrdup(name);
    xasprintf(&fname, "%s/hosts/%s", confbase, name);
    read_config_options(config_tree, name);
    read_config_file(config_tree, fname);
    free(fname);

    if(!read_rsa_private_key())
        return false;

    if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
        myport = xstrdup("655");
    else
        port_specified = true;

    /* Ensure myport is numeric */

    if(!atoi(myport)) {
        struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
        sockaddr_t sa;
        if(!ai || !ai->ai_addr)
            return false;
        free(myport);
        memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
        sockaddr2str(&sa, NULL, &myport);
    }

    get_config_string(lookup_config(config_tree, "Proxy"), &proxy);
    if(proxy) {
        if((space = strchr(proxy, ' ')))
            *space++ = 0;

        if(!strcasecmp(proxy, "none")) {
            proxytype = PROXY_NONE;
        } else if(!strcasecmp(proxy, "socks4")) {
            proxytype = PROXY_SOCKS4;
        } else if(!strcasecmp(proxy, "socks4a")) {
            proxytype = PROXY_SOCKS4A;
        } else if(!strcasecmp(proxy, "socks5")) {
            proxytype = PROXY_SOCKS5;
        } else if(!strcasecmp(proxy, "http")) {
            proxytype = PROXY_HTTP;
        } else if(!strcasecmp(proxy, "exec")) {
            proxytype = PROXY_EXEC;
        } else {
            logger(LOG_ERR, "Unknown proxy type %s!", proxy);
            return false;
        }

        switch(proxytype) {
        case PROXY_NONE:
        default:
            break;

        case PROXY_EXEC:
            if(!space || !*space) {
                logger(LOG_ERR, "Argument expected for proxy type exec!");
                return false;
            }
            proxyhost =  xstrdup(space);
            break;

        case PROXY_SOCKS4:
        case PROXY_SOCKS4A:
        case PROXY_SOCKS5:
        case PROXY_HTTP:
            proxyhost = space;
            if(space && (space = strchr(space, ' ')))
                *space++ = 0, proxyport = space;
            if(space && (space = strchr(space, ' ')))
                *space++ = 0, proxyuser = space;
            if(space && (space = strchr(space, ' ')))
                *space++ = 0, proxypass = space;
            if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) {
                logger(LOG_ERR, "Host and port argument expected for proxy!");
                return false;
            }
            proxyhost = xstrdup(proxyhost);
            proxyport = xstrdup(proxyport);
            if(proxyuser && *proxyuser)
                proxyuser = xstrdup(proxyuser);
            if(proxypass && *proxypass)
                proxypass = xstrdup(proxypass);
            break;
        }

        free(proxy);
    }

    /* Read in all the subnets specified in the host configuration file */

    cfg = lookup_config(config_tree, "Subnet");

    while(cfg) {
        if(!get_config_subnet(cfg, &subnet))
            return false;

        subnet_add(myself, subnet);

        cfg = lookup_config_next(config_tree, cfg);
    }

    /* Check some options */

    if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
        myself->options |= OPTION_INDIRECT;

    if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice)
        myself->options |= OPTION_TCPONLY;

    if(myself->options & OPTION_TCPONLY)
        myself->options |= OPTION_INDIRECT;

    get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
    get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
    get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
    get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
    strictsubnets |= tunnelserver;

    if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
        if(!strcasecmp(mode, "router"))
            routing_mode = RMODE_ROUTER;
        else if(!strcasecmp(mode, "switch"))
            routing_mode = RMODE_SWITCH;
        else if(!strcasecmp(mode, "hub"))
            routing_mode = RMODE_HUB;
        else {
            logger(LOG_ERR, "Invalid routing mode!");
            return false;
        }
        free(mode);
    }

    if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
        if(!strcasecmp(mode, "off"))
            forwarding_mode = FMODE_OFF;
        else if(!strcasecmp(mode, "internal"))
            forwarding_mode = FMODE_INTERNAL;
        else if(!strcasecmp(mode, "kernel"))
            forwarding_mode = FMODE_KERNEL;
        else {
            logger(LOG_ERR, "Invalid forwarding mode!");
            return false;
        }
        free(mode);
    }

    choice = true;
    get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice);
    if(choice)
        myself->options |= OPTION_PMTU_DISCOVERY;

    choice = true;
    get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice);
    if(choice)
        myself->options |= OPTION_CLAMP_MSS;

    get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
    get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
    if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) {
        if(!strcasecmp(mode, "no"))
            broadcast_mode = BMODE_NONE;
        else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst"))
            broadcast_mode = BMODE_MST;
        else if(!strcasecmp(mode, "direct"))
            broadcast_mode = BMODE_DIRECT;
        else {
            logger(LOG_ERR, "Invalid broadcast mode!");
            return false;
        }
        free(mode);
    }

#if !defined(SOL_IP) || !defined(IP_TOS)
    if(priorityinheritance)
        logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
#endif

    if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
        macexpire = 600;

    if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
        if(maxtimeout <= 0) {
            logger(LOG_ERR, "Bogus maximum timeout!");
            return false;
        }
    } else
        maxtimeout = 900;

    if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
        if(udp_rcvbuf <= 0) {
            logger(LOG_ERR, "UDPRcvBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
        if(udp_sndbuf <= 0) {
            logger(LOG_ERR, "UDPSndBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
        if(replaywin_int < 0) {
            logger(LOG_ERR, "ReplayWindow cannot be negative!");
            return false;
        }
        replaywin = (unsigned)replaywin_int;
    }

    if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
        if(!strcasecmp(afname, "IPv4"))
            addressfamily = AF_INET;
        else if(!strcasecmp(afname, "IPv6"))
            addressfamily = AF_INET6;
        else if(!strcasecmp(afname, "any"))
            addressfamily = AF_UNSPEC;
        else {
            logger(LOG_ERR, "Invalid address family!");
            return false;
        }
        free(afname);
    }

    get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);

    /* Generate packet encryption key */

    if(get_config_string
            (lookup_config(config_tree, "Cipher"), &cipher)) {
        if(!strcasecmp(cipher, "none")) {
            myself->incipher = NULL;
        } else {
            myself->incipher = EVP_get_cipherbyname(cipher);

            if(!myself->incipher) {
                logger(LOG_ERR, "Unrecognized cipher type!");
                return false;
            }
        }
    } else
        myself->incipher = EVP_bf_cbc();

    if(myself->incipher)
        myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
    else
        myself->inkeylength = 1;

    myself->connection->outcipher = EVP_bf_ofb();

    if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
        keylifetime = 3600;

    keyexpires = now + keylifetime;

    /* Check if we want to use message authentication codes... */

    if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) {
        if(!strcasecmp(digest, "none")) {
            myself->indigest = NULL;
        } else {
            myself->indigest = EVP_get_digestbyname(digest);

            if(!myself->indigest) {
                logger(LOG_ERR, "Unrecognized digest type!");
                return false;
            }
        }
    } else
        myself->indigest = EVP_sha1();

    myself->connection->outdigest = EVP_sha1();

    if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) {
        if(myself->indigest) {
            if(myself->inmaclength > myself->indigest->md_size) {
                logger(LOG_ERR, "MAC length exceeds size of digest!");
                return false;
            } else if(myself->inmaclength < 0) {
                logger(LOG_ERR, "Bogus MAC length!");
                return false;
            }
        }
    } else
        myself->inmaclength = 4;

    myself->connection->outmaclength = 0;

    /* Compression */

    if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
        if(myself->incompression < 0 || myself->incompression > 11) {
            logger(LOG_ERR, "Bogus compression level!");
            return false;
        }
    } else
        myself->incompression = 0;

    myself->connection->outcompression = 0;

    /* Done */

    myself->nexthop = myself;
    myself->via = myself;
    myself->status.reachable = true;
    node_add(myself);

    graph();

    if(strictsubnets)
        load_all_subnets();

    /* Open device */

    devops = os_devops;

    if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
        if(!strcasecmp(type, "dummy"))
            devops = dummy_devops;
        else if(!strcasecmp(type, "raw_socket"))
            devops = raw_socket_devops;
        else if(!strcasecmp(type, "multicast"))
            devops = multicast_devops;
#ifdef ENABLE_UML
        else if(!strcasecmp(type, "uml"))
            devops = uml_devops;
#endif
#ifdef ENABLE_VDE
        else if(!strcasecmp(type, "vde"))
            devops = vde_devops;
#endif
    }

    if(!devops.setup())
        return false;

    /* Run tinc-up script to further initialize the tap interface */
    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);

    execute_script("tinc-up", envp);

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

    /* Run subnet-up scripts for our own subnets */

    subnet_update(myself, NULL, true);

    /* Open sockets */

    if(!do_detach && getenv("LISTEN_FDS")) {
        sockaddr_t sa;
        socklen_t salen;

        listen_sockets = atoi(getenv("LISTEN_FDS"));
#ifdef HAVE_UNSETENV
        unsetenv("LISTEN_FDS");
#endif

        if(listen_sockets > MAXSOCKETS) {
            logger(LOG_ERR, "Too many listening sockets");
            return false;
        }

        for(i = 0; i < listen_sockets; i++) {
            salen = sizeof sa;
            if(getsockname(i + 3, &sa.sa, &salen) < 0) {
                logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
                return false;
            }

            listen_socket[i].tcp = i + 3;

#ifdef FD_CLOEXEC
            fcntl(i + 3, F_SETFD, FD_CLOEXEC);
#endif

            listen_socket[i].udp = setup_vpn_in_socket(&sa);
            if(listen_socket[i].udp < 0)
                return false;

            ifdebug(CONNECTIONS) {
                hostname = sockaddr2hostname(&sa);
                logger(LOG_NOTICE, "Listening on %s", hostname);
                free(hostname);
            }

            memcpy(&listen_socket[i].sa, &sa, salen);
        }
    } else {
Example #13
0
/*
  Configure node_t mesh->self and set up the local sockets (listen only)
*/
bool setup_myself(meshlink_handle_t *mesh) {
	char *name;
	char *address = NULL;

	if(!(name = get_name(mesh))) {
		logger(mesh, MESHLINK_ERROR, "Name for MeshLink instance required!");
		return false;
	}

	mesh->self = new_node();
	mesh->self->connection = new_connection();
	mesh->self->name = name;
	mesh->self->devclass = mesh->devclass;
	mesh->self->connection->name = xstrdup(name);
	read_host_config(mesh, mesh->config, name);

	if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport)) {
		logger(mesh, MESHLINK_ERROR, "Port for MeshLink instance required!");
		return false;
	}

	mesh->self->connection->options = 0;
	mesh->self->connection->protocol_major = PROT_MAJOR;
	mesh->self->connection->protocol_minor = PROT_MINOR;

	mesh->self->options |= PROT_MINOR << 24;

	if(!read_ecdsa_private_key(mesh))
		return false;

	/* Ensure mesh->myport is numeric */

	if(!atoi(mesh->myport)) {
		struct addrinfo *ai = str2addrinfo("localhost", mesh->myport, SOCK_DGRAM);
		sockaddr_t sa;
		if(!ai || !ai->ai_addr)
			return false;
		free(mesh->myport);
		memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
		sockaddr2str(&sa, NULL, &mesh->myport);
	}

	/* Check some options */

	if(!setup_myself_reloadable(mesh))
		return false;

	/* Compression */

	// TODO: drop compression in the packet layer?
	mesh->self->incompression = 0;
	mesh->self->connection->outcompression = 0;

	/* Done */

	mesh->self->nexthop = mesh->self;
	mesh->self->via = mesh->self;
	mesh->self->status.reachable = true;
	mesh->self->last_state_change = mesh->loop.now.tv_sec;

	node_write_devclass(mesh, mesh->self);
	node_add(mesh, mesh->self);

	graph(mesh);

	load_all_nodes(mesh);

	/* Open sockets */

	mesh->listen_sockets = 0;

	if(!add_listen_address(mesh, address, NULL))
		return false;

	if(!mesh->listen_sockets) {
		logger(mesh, MESHLINK_ERROR, "Unable to create any listening socket!");
		return false;
	}

	xasprintf(&mesh->self->hostname, "MYSELF port %s", mesh->myport);
	mesh->self->connection->hostname = xstrdup(mesh->self->hostname);

	/* Done. */

	mesh->last_config_check = mesh->loop.now.tv_sec;

	return true;
}
Example #14
0
bool ack_h(connection_t *c, const char *request) {
	if(c->protocol_minor == 1)
		return upgrade_h(c, request);

	char hisport[MAX_STRING_SIZE];
	char *hisaddress;
	int weight, mtu;
	uint32_t options;
	node_t *n;
	bool choice;

	if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) {
		logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
			   c->hostname);
		return false;
	}

	/* Check if we already have a node_t for him */

	n = lookup_node(c->name);

	if(!n) {
		n = new_node();
		n->name = xstrdup(c->name);
		node_add(n);
	} else {
		if(n->connection) {
			/* Oh dear, we already have a connection to this node. */
			logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", n->connection->name, n->connection->hostname);

			if(n->connection->outgoing) {
				if(c->outgoing)
					logger(DEBUG_ALWAYS, LOG_WARNING, "Two outgoing connections to the same node!");
				else
					c->outgoing = n->connection->outgoing;

				n->connection->outgoing = NULL;
			}

			terminate_connection(n->connection, false);
			/* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
			graph();
		}
	}

	n->connection = c;
	c->node = n;
	if(!(c->options & options & OPTION_PMTU_DISCOVERY)) {
		c->options &= ~OPTION_PMTU_DISCOVERY;
		options &= ~OPTION_PMTU_DISCOVERY;
	}
	c->options |= options;

	if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu)
		n->mtu = mtu;

	if(get_config_int(lookup_config(config_tree, "PMTU"), &mtu) && mtu < n->mtu)
		n->mtu = mtu;

	if(get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice)) {
		if(choice)
			c->options |= OPTION_CLAMP_MSS;
		else
			c->options &= ~OPTION_CLAMP_MSS;
	}

	/* Activate this connection */

	c->allow_request = ALL;

	logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection with %s (%s) activated", c->name,
			   c->hostname);

	/* Send him everything we know */

	send_everything(c);

	/* Create an edge_t for this connection */

	c->edge = new_edge();
	c->edge->from = myself;
	c->edge->to = n;
	sockaddr2str(&c->address, &hisaddress, NULL);
	c->edge->address = str2sockaddr(hisaddress, hisport);
	free(hisaddress);
	sockaddr_t local_sa;
	socklen_t local_salen = sizeof local_sa;
	if (getsockname(c->socket, &local_sa.sa, &local_salen) < 0)
		logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get local socket address for connection with %s", c->name);
	else {
		char *local_address;
		sockaddr2str(&local_sa, &local_address, NULL);
		c->edge->local_address = str2sockaddr(local_address, myport);
		free(local_address);
	}
	c->edge->weight = (weight + c->estimated_weight) / 2;
	c->edge->connection = c;
	c->edge->options = c->options;

	edge_add(c->edge);

	/* Notify everyone of the new edge */

	if(tunnelserver)
		send_add_edge(c, c->edge);
	else
		send_add_edge(everyone, c->edge);

	/* Run MST and SSSP algorithms */

	graph();

	return true;
}
Example #15
0
static bool send_proxyrequest(connection_t *c) {
	switch(proxytype) {
		case PROXY_HTTP: {
			char *host;
			char *port;

			sockaddr2str(&c->address, &host, &port);
			send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
			free(host);
			free(port);
			return true;
		}
		case PROXY_SOCKS4: {
			if(c->address.sa.sa_family != AF_INET) {
				logger(DEBUG_ALWAYS, LOG_ERR, "Cannot connect to an IPv6 host through a SOCKS 4 proxy!");
				return false;
			}
			char s4req[9 + (proxyuser ? strlen(proxyuser) : 0)];
			s4req[0] = 4;
			s4req[1] = 1;
			memcpy(s4req + 2, &c->address.in.sin_port, 2);
			memcpy(s4req + 4, &c->address.in.sin_addr, 4);
			if(proxyuser)
				memcpy(s4req + 8, proxyuser, strlen(proxyuser));
			s4req[sizeof s4req - 1] = 0;
			c->tcplen = 8;
			return send_meta(c, s4req, sizeof s4req);
		}
		case PROXY_SOCKS5: {
			int len = 3 + 6 + (c->address.sa.sa_family == AF_INET ? 4 : 16);
			c->tcplen = 2;
			if(proxypass)
				len += 3 + strlen(proxyuser) + strlen(proxypass);
			char s5req[len];
			int i = 0;
			s5req[i++] = 5;
			s5req[i++] = 1;
			if(proxypass) {
				s5req[i++] = 2;
				s5req[i++] = 1;
				s5req[i++] = strlen(proxyuser);
				memcpy(s5req + i, proxyuser, strlen(proxyuser));
				i += strlen(proxyuser);
				s5req[i++] = strlen(proxypass);
				memcpy(s5req + i, proxypass, strlen(proxypass));
				i += strlen(proxypass);
				c->tcplen += 2;
			} else {
				s5req[i++] = 0;
			}
			s5req[i++] = 5;
			s5req[i++] = 1;
			s5req[i++] = 0;
			if(c->address.sa.sa_family == AF_INET) {
				s5req[i++] = 1;
				memcpy(s5req + i, &c->address.in.sin_addr, 4);
				i += 4;
				memcpy(s5req + i, &c->address.in.sin_port, 2);
				i += 2;
				c->tcplen += 10;
			} else if(c->address.sa.sa_family == AF_INET6) {
				s5req[i++] = 3;
				memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
				i += 16;
				memcpy(s5req + i, &c->address.in6.sin6_port, 2);
				i += 2;
				c->tcplen += 22;
			} else {
				logger(DEBUG_ALWAYS, LOG_ERR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
				return false;
			}
			if(i > len)
				abort();
			return send_meta(c, s5req, sizeof s5req);
		}
		case PROXY_SOCKS4A:
			logger(DEBUG_ALWAYS, LOG_ERR, "Proxy type not implemented yet");
			return false;
		case PROXY_EXEC:
			return true;
		default:
			logger(DEBUG_ALWAYS, LOG_ERR, "Unknown proxy type");
			return false;
	}
}
Example #16
0
void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
	avl_node_t *node;
	int i;
	char *envp[10] = {NULL};
	char netstr[MAXNETSTR];
	char *name, *address, *port;
	char empty[] = "";

	// Prepare environment variables to be passed to the script

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

	if(owner != myself) {
		sockaddr2str(&owner->address, &address, &port);
		// 4 and 5 are reserved for SUBNET and WEIGHT
		xasprintf(&envp[6], "REMOTEADDRESS=%s", address);
		xasprintf(&envp[7], "REMOTEPORT=%s", port);
		free(port);
		free(address);
	}

	xasprintf(&envp[8], "NAME=%s", myself->name);

	name = up ? "subnet-up" : "subnet-down";

	if(!subnet) {
		for(node = owner->subnet_tree->head; node; node = node->next) {
			subnet = node->data;
			if(!net2str(netstr, sizeof netstr, subnet))
				continue;
			// Strip the weight from the subnet, and put it in its own environment variable
			char *weight = strchr(netstr, '#');
			if(weight)
				*weight++ = 0;
			else
				weight = empty;

			// Prepare the SUBNET and WEIGHT variables
			if(envp[4])
				free(envp[4]);
			if(envp[5])
				free(envp[5]);
			xasprintf(&envp[4], "SUBNET=%s", netstr);
			xasprintf(&envp[5], "WEIGHT=%s", weight);

			execute_script(name, envp);
		}
	} else {
		if(net2str(netstr, sizeof netstr, subnet)) {
			// Strip the weight from the subnet, and put it in its own environment variable
			char *weight = strchr(netstr, '#');
			if(weight)
				*weight++ = 0;
			else
				weight = empty;

			// Prepare the SUBNET and WEIGHT variables
			xasprintf(&envp[4], "SUBNET=%s", netstr);
			xasprintf(&envp[5], "WEIGHT=%s", weight);

			execute_script(name, envp);
		}
	}

	for(i = 0; envp[i] && i < 9; i++)
		free(envp[i]);
}
Example #17
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;
}
Example #18
0
bool send_proxyrequest(connection_t *c) {
	switch(proxytype) {
	case PROXY_SOCKS4:
		if(c->address.sa.sa_family != AF_INET) {
			logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!");
			return false;
		}
	case PROXY_SOCKS4A: {
		if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) {
			logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!");
			return false;
		}
		int len = 9;
		if(proxyuser)
			len += strlen(proxyuser);
		if(c->address.sa.sa_family == AF_UNKNOWN)
			len += 1 + strlen(c->address.unknown.address);
		char s4req[len];
		s4req[0] = 4;
		s4req[1] = 1;
		if(c->address.sa.sa_family == AF_INET) {
			memcpy(s4req + 2, &c->address.in.sin_port, 2);
			memcpy(s4req + 4, &c->address.in.sin_addr, 4);
		} else {
			uint16_t port = htons(atoi(c->address.unknown.port));
			memcpy(s4req + 2, &port, 2);
			memcpy(s4req + 4, "\0\0\0\1", 4);
			strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address);
		}
		if(proxyuser)
			strcpy(s4req + 8, proxyuser);
		else
			s4req[8] = 0;
		s4req[sizeof s4req - 1] = 0;
		c->allow_request = PROXY;
		return send_meta(c, s4req, sizeof s4req);
	}

	case PROXY_SOCKS5: {
		int len = 3 + 6;
		if(c->address.sa.sa_family == AF_INET) {
			len += 4;
		} else if(c->address.sa.sa_family == AF_INET6) {
			len += 16;
		} else if(c->address.sa.sa_family == AF_UNKNOWN) {
			len += 1 + strlen(c->address.unknown.address);
		} else {
			logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
			return false;
		}
		if(proxypass)
			len += 3 + strlen(proxyuser) + strlen(proxypass);
		char s5req[len];
		int i = 0;
		s5req[i++] = 5;
		s5req[i++] = 1;
		if(proxypass) {
			s5req[i++] = 2;
			s5req[i++] = 1;
			s5req[i++] = strlen(proxyuser);
			strcpy(s5req + i, proxyuser);
			i += strlen(proxyuser);
			s5req[i++] = strlen(proxypass);
			strcpy(s5req + i, proxypass);
			i += strlen(proxypass);
		} else {
			s5req[i++] = 0;
		}
		s5req[i++] = 5;
		s5req[i++] = 1;
		s5req[i++] = 0;
		if(c->address.sa.sa_family == AF_INET) {
			s5req[i++] = 1;
			memcpy(s5req + i, &c->address.in.sin_addr, 4);
			i += 4;
			memcpy(s5req + i, &c->address.in.sin_port, 2);
			i += 2;
		} else if(c->address.sa.sa_family == AF_INET6) {
			s5req[i++] = 4;
			memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
			i += 16;
			memcpy(s5req + i, &c->address.in6.sin6_port, 2);
			i += 2;
		} else if(c->address.sa.sa_family == AF_UNKNOWN) {
			s5req[i++] = 3;
			int len = strlen(c->address.unknown.address);
			s5req[i++] = len;
			memcpy(s5req + i, c->address.unknown.address, len);
			i += len;
			uint16_t port = htons(atoi(c->address.unknown.port));
			memcpy(s5req + i, &port, 2);
			i += 2;
		} else {
			logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy");
			return false;
		}
		if(i > len)
			abort();
		c->allow_request = PROXY;
		return send_meta(c, s5req, sizeof s5req);
	}

	case PROXY_HTTP: {
		char *host;
		char *port;

		sockaddr2str(&c->address, &host, &port);
		send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
		free(host);
		free(port);
		c->allow_request = PROXY;
		return true;
	}

	case PROXY_EXEC:
		return true;

	default:
		logger(LOG_ERR, "Unknown proxy type");
		return false;
	}
}