1#include <err.h>2#include <dtls.h>3#include <dtls_debug.h>4#include <poll.h>5#include <stdio.h>6#include <stdlib.h>7#include <string.h>8#include <unistd.h>910#include "dat.h"11#include "fns.h"1213/**14 * The session used for the DTLS socket.15 */16session_t dsess;1718/**19 * The address of the client socket from which we last20 * received a datagram.21 *22 * XXX: We don't support multiple clients.23 */24session_t csess;2526/**27 * Whether dunnel was started in server mode using -s.28 */29int smode;3031/**32 * The global DTLS context.33 */34static dtls_context_t *ctx;3536#define newpollfd(FD) \37 (struct pollfd){.fd = FD, .events = POLLIN | POLLERR};3839static void40usage(char *progname)41{42 fprintf(stderr, "Usage: %s "43 "-s -v [LOG LEVEL] -a [ADDR] -p [PORT] "44 "-i [ID FILE] -k [KEY FILE] "45 "DTLS_HOST DTLS_PORT\n", progname);46 exit(EXIT_FAILURE);47}4849static void50handle(int fd, struct dctx *dctx)51{52 ssize_t r;53 session_t sess, *sptr;54 unsigned char buf[DTLS_MAX_BUF];5556 memset(&sess, '\0', sizeof(sess));57 if (dctx->ufd == fd) {58 sptr = (smode) ? &sess : &csess;59 } else { /* dtls socket */60 sptr = (smode) ? &csess : &sess;61 }6263 sptr->size = sizeof(sptr->addr);64 if ((r = recvfrom(fd, buf, DTLS_MAX_BUF, MSG_DONTWAIT,65 &sptr->addr.sa, &sptr->size)) == -1) {66 warn("recvfrom failed");67 return;68 }6970 if (dctx->ufd == fd) {71 sptr = (smode) ? &csess : &dsess;72 if (dtls_write(ctx, sptr, buf, r) == -1) {73 warnx("dtls_write failed");74 return;75 }76 } else {77 dtls_handle_message(ctx, sptr, buf, r);78 }79}8081static void82ploop(struct dctx *dctx)83{84 size_t i;85 short ev;86 nfds_t nfds;87 int fd, ufd, dfd;88 struct pollfd fds[2];8990 nfds = sizeof(fds) / sizeof(fds[0]);91 dfd = dctx->dfd;92 ufd = dctx->ufd;9394 fds[0] = newpollfd(dfd);95 fds[1] = newpollfd(ufd);9697 for (;;) {98 if (poll(fds, nfds, -1) == -1)99 err(EXIT_FAILURE, "poll failed");100101 for (i = 0; i < nfds; i++) {102 fd = fds[i].fd;103 ev = fds[i].revents;104105 if (ev & POLLIN) {106 handle(fd, dctx);107 } else if (ev & POLLERR) {108 errx(EXIT_FAILURE, "Received POLLERR on %s socket\n",109 (fd == ufd) ? "UDP" : "DTLS");110 }111 }112 }113}114115int116main(int argc, char **argv)117{118 int opt, ufd;119 sockop uop, dop;120 unsigned char *key, *id;121 char *uaddr, *uport, *daddr, *dport;122123 smode = 0;124 uaddr = uport = NULL;125 key = id = NULL;126127 dtls_init();128 while ((opt = getopt(argc, argv, "a:i:k:p:sv:")) != -1) {129 switch (opt) {130 case 'a':131 uaddr = optarg;132 break;133 case 'i':134 if (!(id = readfile(optarg)))135 err(EXIT_FAILURE, "couldn't read identity");136 break;137 case 'k':138 if (!(key = readfile(optarg)))139 err(EXIT_FAILURE, "couldn't read key");140 break;141 case 'p':142 uport = optarg;143 break;144 case 's': /* act as dtls server, default: act as dtls client */145 smode = 1;146 break;147 case 'v':148 dtls_set_log_level(atoi(optarg));149 break;150 default:151 usage(*argv);152 break;153 }154 }155156 if (smode) {157 uop = SOCK_CONN;158 dop = SOCK_BIND;159 } else {160 uop = SOCK_BIND;161 dop = SOCK_CONN;162 }163164 if (argc <= 2 || optind + 1 >= argc)165 usage(*argv);166 else if (!key || !id)167 errx(EXIT_FAILURE, "A key and an identity must be provided");168169 daddr = argv[optind];170 dport = argv[optind + 1];171172 if ((ufd = usock(uaddr, (!uport) ? dport : uport, uop)) == -1)173 err(EXIT_FAILURE, "usock failed");174 if (!(ctx = dsock(daddr, dport, id, key, ufd, dop)))175 err(EXIT_FAILURE, "dsock failed");176177 ploop(dtls_get_app_data(ctx));178 return EXIT_SUCCESS;179}