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>
9
10#include "dat.h"
11#include "fns.h"
12
13/**
14 * The session used for the DTLS socket.
15 */
16session_t dsess;
17
18/**
19 * The address of the client socket from which we last
20 * received a datagram.
21 *
22 * XXX: We don't support multiple clients.
23 */
24session_t csess;
25
26/**
27 * Whether dunnel was started in server mode using -s.
28 */
29int smode;
30
31/**
32 * The global DTLS context.
33 */
34static dtls_context_t *ctx;
35
36#define newpollfd(FD) \
37 (struct pollfd){.fd = FD, .events = POLLIN | POLLERR};
38
39static void
40usage(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}
48
49static void
50handle(int fd, struct dctx *dctx)
51{
52 ssize_t r;
53 session_t sess, *sptr;
54 unsigned char buf[DTLS_MAX_BUF];
55
56 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 }
62
63 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 }
69
70 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}
80
81static void
82ploop(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];
89
90 nfds = sizeof(fds) / sizeof(fds[0]);
91 dfd = dctx->dfd;
92 ufd = dctx->ufd;
93
94 fds[0] = newpollfd(dfd);
95 fds[1] = newpollfd(ufd);
96
97 for (;;) {
98 if (poll(fds, nfds, -1) == -1)
99 err(EXIT_FAILURE, "poll failed");
100
101 for (i = 0; i < nfds; i++) {
102 fd = fds[i].fd;
103 ev = fds[i].revents;
104
105 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}
114
115int
116main(int argc, char **argv)
117{
118 int opt, ufd;
119 sockop uop, dop;
120 unsigned char *key, *id;
121 char *uaddr, *uport, *daddr, *dport;
122
123 smode = 0;
124 uaddr = uport = NULL;
125 key = id = NULL;
126
127 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 }
155
156 if (smode) {
157 uop = SOCK_CONN;
158 dop = SOCK_BIND;
159 } else {
160 uop = SOCK_BIND;
161 dop = SOCK_CONN;
162 }
163
164 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");
168
169 daddr = argv[optind];
170 dport = argv[optind + 1];
171
172 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");
176
177 ploop(dtls_get_app_data(ctx));
178 return EXIT_SUCCESS;
179}