static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
				  char *buff, size_t len)
{
	int dfd, keep = 1;
	char *cbuff;
	ssize_t rlen, err, clen;
	struct ct_proto *hdr;
	struct curve25519_proto *p;
	struct sockaddr_storage naddr;
	socklen_t nlen;
	size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;

	if (!buff || len <= off)
		return 0;

	memset(buff, 0, len);
	while ((rlen = read(fd, buff + off, len - off)) > 0) {
		dfd = -1; nlen = 0; p = NULL;

		memset(&naddr, 0, sizeof(naddr));

		hdr = (struct ct_proto *) buff;
		memset(hdr, 0, sizeof(*hdr));
		hdr->flags = 0;

		trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr,
				 (size_t *) &nlen);
		if (unlikely(dfd < 0 || nlen == 0)) {
			memset(buff, 0, len);
			continue;
		}

		err = get_user_by_sockaddr(&naddr, nlen, &p);
		if (unlikely(err || !p)) {
			memset(buff, 0, len);
			continue;
		}

		clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
					 crypto_box_zerobytes), (rlen +
					 crypto_box_zerobytes), (unsigned char **)
					 &cbuff);
		if (unlikely(clen <= 0)) {
			memset(buff, 0, len);
			continue;
		}

		hdr->payload = htons((uint16_t) clen);

		set_udp_cork(dfd);

		sendto(dfd, hdr, sizeof(struct ct_proto), 0, (struct sockaddr *)
		       &naddr, nlen);
		sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr, nlen);

		set_udp_uncork(dfd);

		memset(buff, 0, len);
	}

	return keep;
}
Exemple #2
0
static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
				  char *buff, size_t len)
{
	int dfd, state, keep = 1;
	char *cbuff;
	ssize_t rlen, err, clen;
	struct ct_proto *hdr;
	struct curve25519_proto *p;
	struct sockaddr_storage naddr;
	socklen_t nlen;
	size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;

	if (!buff || len <= off) {
		errno = EINVAL;
		return 0;
	}

	errno = 0;
	memset(buff, 0, len);
	while ((rlen = read(fd, buff + off, len - off)) > 0) {
		dfd = -1;
		nlen = 0;
		p = NULL;
		memset(&naddr, 0, sizeof(naddr));

		hdr = (struct ct_proto *) buff;
		memset(hdr, 0, sizeof(*hdr));
		hdr->flags = 0;

		trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr,
				 (size_t *) &nlen);
		if (unlikely(dfd < 0 || nlen == 0)) {
			syslog(LOG_INFO, "CPU%u: UDP tunnel lookup failed: "
			       "unknown destination\n", ws->cpu);
			memset(buff, 0, len);
			continue;
		}
		err = get_user_by_sockaddr(&naddr, nlen, &p);
		if (unlikely(err || !p)) {
			syslog(LOG_ERR, "CPU%u: User protocol not in cache! "
			       "Dropping connection!\n", ws->cpu);
			memset(buff, 0, len);
			continue;
		}
		clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
					 crypto_box_zerobytes), (rlen +
					 crypto_box_zerobytes), (unsigned char **)
					 &cbuff);
		if (unlikely(clen <= 0)) {
			syslog(LOG_ERR, "CPU%u: UDP tunnel encrypt error: %zd\n",
			       ws->cpu, clen);
			memset(buff, 0, len);
			continue;
		}

		hdr->payload = htons((uint16_t) clen);

		state = 1;
		setsockopt(dfd, IPPROTO_UDP, UDP_CORK, &state, sizeof(state));

		err = sendto(dfd, hdr, sizeof(struct ct_proto), 0,
			     (struct sockaddr *) &naddr, nlen);
		if (unlikely(err < 0))
			syslog(LOG_ERR, "CPU%u: UDP tunnel write error: %s\n",
			       ws->cpu, strerror(errno));

		err = sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr,
			     nlen);
		if (unlikely(err < 0))
			syslog(LOG_ERR, "CPU%u: UDP tunnel write error: %s\n",
			       ws->cpu, strerror(errno));

		state = 0;
		setsockopt(dfd, IPPROTO_UDP, UDP_CORK, &state, sizeof(state));

		errno = 0;
		memset(buff, 0, len);
	}

	if (unlikely(rlen < 0 && errno != EAGAIN))
		syslog(LOG_ERR, "CPU%u: UDP tunnel read error: %s\n",
		       ws->cpu, strerror(errno));

	return keep;
}
static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
				  char *buff, size_t len)
{
	int keep = 1;
	char *cbuff;
	ssize_t rlen, err, clen;
	struct ct_proto *hdr;
	struct curve25519_proto *p;
	struct sockaddr_storage naddr;
	socklen_t nlen = sizeof(naddr);

	if (!buff || !len)
		return 0;

	memset(&naddr, 0, sizeof(naddr));
	while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr,
				&nlen)) > 0) {
		p = NULL;

		hdr = (struct ct_proto *) buff;

		if (unlikely(rlen < sizeof(struct ct_proto)))
			goto close;
		if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
			goto close;
		if (unlikely(ntohs(hdr->payload) == 0))
			goto close;
		if (hdr->flags & PROTO_FLAG_EXIT) {
close:
			remove_user_by_sockaddr(&naddr, nlen);
			trie_addr_remove_addr(&naddr, nlen);
			handler_udp_notify_close(fd, &naddr);

			return keep;
		}
		if (hdr->flags & PROTO_FLAG_INIT) {
			syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
				     "from remote end!\n");

			if (unlikely(rlen - sizeof(*hdr) <
				     sizeof(struct username_struct)))
				goto close;

			err = try_register_user_by_sockaddr(ws->c,
					buff + sizeof(struct ct_proto),
					rlen - sizeof(struct ct_proto),
					&naddr, nlen, auth_log);
			if (unlikely(err))
				goto close;

			goto next;
		}

		err = get_user_by_sockaddr(&naddr, nlen, &p);
		if (unlikely(err || !p))
			goto close;

		clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
					 sizeof(struct ct_proto),
					 rlen - sizeof(struct ct_proto),
					 (unsigned char **) &cbuff, NULL);
                if (unlikely(clen <= 0))
			goto close;

		cbuff += crypto_box_zerobytes;
		clen -= crypto_box_zerobytes;

		err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
					     fd, &naddr, nlen);
		if (unlikely(err))
			goto next;

		err = write(ws->parent.tunfd, cbuff, clen);
next:
		nlen = sizeof(naddr);
		memset(&naddr, 0, sizeof(naddr));
	}

	return keep;
}
Exemple #4
0
static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
				  char *buff, size_t len)
{
	int keep = 1;
	char *cbuff;
	ssize_t rlen, err, clen;
	struct ct_proto *hdr;
	struct curve25519_proto *p;
	struct sockaddr_storage naddr;
	socklen_t nlen = sizeof(naddr);

	if (!buff || !len) {
		errno = EINVAL;
		return 0;
	}

	memset(&naddr, 0, sizeof(naddr));

	errno = 0;
	while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr,
				&nlen)) > 0) {
		p = NULL;
		hdr = (struct ct_proto *) buff;

		if (unlikely(rlen < sizeof(struct ct_proto)))
			goto close;
		if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
			goto close;
		if (unlikely(ntohs(hdr->payload) == 0))
			goto close;
		if (hdr->flags & PROTO_FLAG_EXIT) {
close:
			remove_user_by_sockaddr(&naddr, nlen);
			trie_addr_remove_addr(&naddr, nlen);
			handler_udp_notify_close(fd, &naddr);
			return keep;
		}
		if (hdr->flags & PROTO_FLAG_INIT) {
			if (auth_log)
				syslog(LOG_INFO, "Got initial userhash from remote end!\n");
			if (unlikely(rlen - sizeof(*hdr) <
				     sizeof(struct username_struct)))
				goto close;
			err = try_register_user_by_sockaddr(ws->c, buff + sizeof(struct ct_proto),
							    rlen - sizeof(struct ct_proto),
							    &naddr, nlen, auth_log);
			if (unlikely(err))
				goto close;
			goto next;
		}

		err = get_user_by_sockaddr(&naddr, nlen, &p);
		if (unlikely(err || !p)) {
			syslog(LOG_ERR, "CPU%u: User protocol not in cache! "
			       "Dropping connection!\n", ws->cpu);
			goto close;
		}
		clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
					 sizeof(struct ct_proto),
					 rlen - sizeof(struct ct_proto),
					 (unsigned char **) &cbuff, NULL);
                if (unlikely(clen <= 0)) {
			syslog(LOG_ERR, "CPU%u: UDP net decryption error: %zd\n",
			       ws->cpu, clen);
			goto close;
		}
		cbuff += crypto_box_zerobytes;
		clen -= crypto_box_zerobytes;
		err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
					     fd, &naddr, nlen);
		if (unlikely(err)) {
			syslog(LOG_INFO, "CPU%u: Malicious packet dropped "
			       "from id %d\n", ws->cpu, fd);
			goto next;
		}

		err = write(ws->parent.tunfd, cbuff, clen);
		if (unlikely(err < 0))
			syslog(LOG_ERR, "CPU%u: UDP net write error: %s\n",
			       ws->cpu, strerror(errno));

next:
		nlen = sizeof(naddr);
		memset(&naddr, 0, sizeof(naddr));
		errno = 0;
	}

	if (unlikely(rlen < 0 && errno != EAGAIN))
		syslog(LOG_ERR, "CPU%u: UDP net read error: %s\n",
		       ws->cpu, strerror(errno));

	return keep;
}