dunnel

An experimental DTLS proxy

git clone https://git.8pit.net/dunnel.git

  1#include <dtls.h>
  2#include <errno.h>
  3#include <netdb.h>
  4#include <stdlib.h>
  5#include <assert.h>
  6
  7#include <sys/types.h>
  8#include <sys/socket.h>
  9
 10#include "dat.h"
 11
 12static socklen_t
 13str2addr(char *host, char *port, struct sockaddr *dest)
 14{
 15	socklen_t len;
 16	struct addrinfo hint, *res, *r;
 17
 18	memset(&hint, '\0', sizeof(hint));
 19	hint.ai_family = AF_UNSPEC;
 20	hint.ai_socktype = SOCK_DGRAM;
 21
 22	if (getaddrinfo(host, port, &hint, &res)) {
 23		errno = EAFNOSUPPORT;
 24		return 0;
 25	}
 26
 27	len = 0;
 28	for (r = res; r != NULL; r = r->ai_next) {
 29		switch (r->ai_family) {
 30		case AF_INET6:
 31		case AF_INET:
 32			len = r->ai_addrlen;
 33			memcpy(dest, r->ai_addr, len);
 34			goto ret;
 35		default:
 36			errno = EADDRNOTAVAIL;
 37			goto ret;
 38		}
 39	}
 40
 41	errno = EADDRNOTAVAIL;
 42ret:
 43	freeaddrinfo(res);
 44	return len;
 45}
 46
 47static int
 48sock(char *host, char *port, struct sockaddr *addr, socklen_t *alen)
 49{
 50	int fd;
 51
 52	/* From getaddrinfo(3)
 53	 *   The nodename and servname arguments are either null
 54	 *   pointers or pointers to null-terminated strings. One or
 55	 *   both of these two arguments shall be supplied by the
 56	 *   application as a non-null pointer.
 57	 */
 58	assert(host != NULL || port != NULL);
 59	if (!(*alen = str2addr(host, port, addr)))
 60		return -1;
 61
 62	if ((fd = socket(addr->sa_family, SOCK_DGRAM, 0)) == -1)
 63		return -1;
 64
 65	return fd;
 66}
 67
 68int
 69usock(char *host, char *port, sockop op)
 70{
 71	int fd;
 72	socklen_t alen;
 73	struct sockaddr_storage addr;
 74
 75	if ((fd = sock(host, port, (struct sockaddr*)&addr, &alen)) == -1)
 76		return -1;
 77
 78	switch (op) {
 79	case SOCK_CONN:
 80		if ((connect(fd, (struct sockaddr*)&addr, alen)) == -1)
 81			return -1;
 82		break;
 83	case SOCK_BIND:
 84		if ((bind(fd, (struct sockaddr*)&addr, alen)) == -1)
 85			return -1;
 86		break;
 87	default: /* unknown operation */
 88		errno = EINVAL;
 89		return -1;
 90	}
 91
 92	return fd;
 93}
 94
 95dtls_context_t*
 96dsock(char *host, char *port, unsigned char *id,
 97	unsigned char *key, int ufd, sockop op)
 98{
 99	int fd;
100	struct dctx *dctx;
101	dtls_context_t *ctx;
102
103	if (!(dctx = malloc(sizeof(*dctx))))
104		return NULL;
105
106	memset(&dsess, '\0', sizeof(dsess));
107	if ((fd = sock(host, port, &dsess.addr.sa, &dsess.size)) == -1)
108		return NULL;
109
110	dctx->ufd = ufd;
111	dctx->dfd = fd;
112	dctx->key = key;
113	dctx->id = id;
114
115	if (!(ctx = dtls_new_context(dctx))) {
116		errno = ENOMEM;
117		return NULL;
118	}
119
120	dtls_set_handler(ctx, &dtlscb);
121	switch (op) {
122	case SOCK_CONN:
123		if (dtls_connect(ctx, &dsess) < 0) {
124			errno = ECONNREFUSED;
125			return NULL;
126		}
127		break;
128	case SOCK_BIND:
129		if (bind(dctx->dfd, (struct sockaddr*)&dsess.addr.sa, dsess.size) == -1)
130			return NULL;
131		break;
132	default: /* unknown operation */
133		errno = EINVAL;
134		return NULL;
135	}
136
137	return ctx;
138}