ring: add necessary structures and helper functions for v3
[netsniff-ng.git] / ct_client.c
blobdbf07c51c51703dfbaf93a00174f38958ea0b6e1
1 /*
2 * curvetun - the cipherspace wormhole creator
3 * Part of the netsniff-ng project
4 * Copyright 2011 Daniel Borkmann <daniel@netsniff-ng.org>,
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <netdb.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <syslog.h>
16 #include <limits.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/poll.h>
24 #include <netinet/tcp.h>
25 #include <netinet/udp.h>
26 #include <linux/if_tun.h>
28 #include "built_in.h"
29 #include "die.h"
30 #include "xio.h"
31 #include "xutils.h"
32 #include "curve.h"
33 #include "xmalloc.h"
34 #include "curvetun.h"
35 #include "ct_servmgmt.h"
36 #include "ct_usermgmt.h"
37 #include "crypto_auth_hmacsha512256.h"
39 extern volatile sig_atomic_t sigint;
40 static volatile sig_atomic_t closed_by_server = 0;
42 static void handler_udp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
43 struct curve25519_struct *c, char *buff,
44 size_t len)
46 char *cbuff;
47 ssize_t rlen, clen;
48 struct ct_proto *hdr;
49 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
51 if (!buff || len <= off)
52 return;
54 memset(buff, 0, len);
55 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
56 hdr = (struct ct_proto *) buff;
58 memset(hdr, 0, sizeof(*hdr));
59 hdr->flags = 0;
61 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
62 crypto_box_zerobytes), (rlen +
63 crypto_box_zerobytes), (unsigned char **)
64 &cbuff);
65 if (unlikely(clen <= 0))
66 goto close;
68 hdr->payload = htons((uint16_t) clen);
70 set_udp_cork(dfd);
72 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
73 write_exact(dfd, cbuff, clen, 0);
75 set_udp_uncork(dfd);
77 memset(buff, 0, len);
80 return;
81 close:
82 closed_by_server = 1;
85 static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
86 struct curve25519_struct *c, char *buff,
87 size_t len)
89 char *cbuff;
90 ssize_t rlen, clen;
91 struct ct_proto *hdr;
92 struct sockaddr_storage naddr;
94 socklen_t nlen = sizeof(naddr);
96 if (!buff || !len)
97 return;
99 memset(&naddr, 0, sizeof(naddr));
100 while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr,
101 &nlen)) > 0) {
102 hdr = (struct ct_proto *) buff;
104 if (unlikely(rlen < sizeof(struct ct_proto)))
105 goto close;
106 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
107 goto close;
108 if (unlikely(ntohs(hdr->payload) == 0))
109 goto close;
110 if (hdr->flags & PROTO_FLAG_EXIT)
111 goto close;
113 clen = curve25519_decode(c, p, (unsigned char *) buff +
114 sizeof(struct ct_proto),
115 rlen - sizeof(struct ct_proto),
116 (unsigned char **) &cbuff, NULL);
117 if (unlikely(clen <= 0))
118 goto close;
120 cbuff += crypto_box_zerobytes;
121 clen -= crypto_box_zerobytes;
123 if (write(dfd, cbuff, clen)) { ; }
126 return;
127 close:
128 closed_by_server = 1;
131 static void handler_tcp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
132 struct curve25519_struct *c, char *buff,
133 size_t len)
135 char *cbuff;
136 ssize_t rlen, clen;
137 struct ct_proto *hdr;
138 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
140 if (!buff || len <= off)
141 return;
143 memset(buff, 0, len);
144 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
145 hdr = (struct ct_proto *) buff;
147 memset(hdr, 0, sizeof(*hdr));
148 hdr->flags = 0;
150 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
151 crypto_box_zerobytes), (rlen +
152 crypto_box_zerobytes), (unsigned char **)
153 &cbuff);
154 if (unlikely(clen <= 0))
155 goto close;
157 hdr->payload = htons((uint16_t) clen);
159 set_tcp_cork(dfd);
161 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
162 write_exact(dfd, cbuff, clen, 0);
164 set_tcp_uncork(dfd);
166 memset(buff, 0, len);
169 return;
170 close:
171 closed_by_server = 1;
174 extern ssize_t handler_tcp_read(int fd, char *buff, size_t len);
176 static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
177 struct curve25519_struct *c, char *buff,
178 size_t len)
180 char *cbuff;
181 ssize_t rlen, clen;
182 struct ct_proto *hdr;
184 if (!buff || !len)
185 return;
187 while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) {
188 hdr = (struct ct_proto *) buff;
190 if (unlikely(rlen < sizeof(struct ct_proto)))
191 goto close;
192 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
193 goto close;
194 if (unlikely(ntohs(hdr->payload) == 0))
195 goto close;
196 if (hdr->flags & PROTO_FLAG_EXIT)
197 goto close;
199 clen = curve25519_decode(c, p, (unsigned char *) buff +
200 sizeof(struct ct_proto),
201 rlen - sizeof(struct ct_proto),
202 (unsigned char **) &cbuff, NULL);
203 if (unlikely(clen <= 0))
204 goto close;
206 cbuff += crypto_box_zerobytes;
207 clen -= crypto_box_zerobytes;
209 if (write(dfd, cbuff, clen)) { ; }
212 return;
213 close:
214 closed_by_server = 1;
217 static void notify_init(int fd, int udp, struct curve25519_proto *p,
218 struct curve25519_struct *c, char *home)
220 int fd2, i;
221 ssize_t err, clen;
222 size_t us_len, msg_len, pad;
223 struct ct_proto hdr;
224 char username[256], path[PATH_MAX], *us, *cbuff, *msg;
225 unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;
227 memset(&hdr, 0, sizeof(hdr));
228 hdr.flags |= PROTO_FLAG_INIT;
230 memset(path, 0, sizeof(path));
231 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
233 fd2 = open_or_die(path, O_RDONLY);
235 memset(username, 0, sizeof(username));
236 err = read(fd2, username, sizeof(username));
237 username[sizeof(username) - 1] = 0;
239 close(fd2);
241 token = get_serv_store_entry_auth_token();
242 if (!token)
243 syslog_panic("Cannot find auth token for server!\n");
245 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
246 us = xzmalloc(us_len);
248 err = username_msg(username, strlen(username) + 1,
249 us + crypto_box_zerobytes,
250 us_len - crypto_box_zerobytes);
251 if (unlikely(err))
252 syslog_panic("Cannot create init message!\n");
254 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
255 (unsigned char **) &cbuff);
256 if (unlikely(clen <= 0))
257 syslog_panic("Init encrypt error!\n");
259 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
260 if (unlikely(err))
261 syslog_panic("Cannot create init hmac message!\n");
263 pad = ((uint32_t) secrand()) % 200;
264 msg_len = clen + sizeof(auth) + pad;
266 msg = xzmalloc(msg_len);
267 memcpy(msg, auth, sizeof(auth));
268 memcpy(msg + sizeof(auth), cbuff, clen);
270 for (i = sizeof(auth) + clen; i < msg_len; ++i)
271 msg[i] = (uint8_t) secrand();
273 hdr.payload = htons((uint16_t) msg_len);
275 set_sock_cork(fd, udp);
277 write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
278 write_exact(fd, msg, msg_len, 0);
280 set_sock_uncork(fd, udp);
282 xfree(msg);
283 xfree(us);
286 static void notify_close(int fd)
288 struct ct_proto hdr;
290 memset(&hdr, 0, sizeof(hdr));
292 hdr.flags |= PROTO_FLAG_EXIT;
293 hdr.payload = 0;
295 write_exact(fd, &hdr, sizeof(hdr), 0);
298 int client_main(char *home, char *dev, char *host, char *port, int udp)
300 int fd = -1, tunfd = 0, retry_server = 0;
301 int ret, try = 1, i;
302 struct addrinfo hints, *ahead, *ai;
303 struct pollfd fds[2];
304 struct curve25519_proto *p;
305 struct curve25519_struct *c;
306 char *buff;
307 size_t blen = TUNBUFF_SIZ; //FIXME
309 retry:
310 if (!retry_server) {
311 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
312 syslog(LOG_INFO, "curvetun client booting!\n");
315 c = xmalloc(sizeof(struct curve25519_struct));
317 curve25519_alloc_or_maybe_die(c);
319 p = get_serv_store_entry_proto_inf();
320 if (!p)
321 syslog_panic("Cannot proto!\n");
323 memset(&hints, 0, sizeof(hints));
324 hints.ai_family = PF_UNSPEC;
325 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
326 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
327 hints.ai_flags = AI_NUMERICSERV;
329 ret = getaddrinfo(host, port, &hints, &ahead);
330 if (ret < 0) {
331 syslog(LOG_ERR, "Cannot get address info! Retry!\n");
332 curve25519_free(c);
333 xfree(c);
334 fd = -1;
335 retry_server = 1;
336 closed_by_server = 0;
337 sleep(1);
338 goto retry;
341 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
342 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
343 if (fd < 0)
344 continue;
345 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
346 if (ret < 0) {
347 syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
348 try++, strerror(errno));
349 close(fd);
350 fd = -1;
351 continue;
354 set_socket_keepalive(fd);
355 set_mtu_disc_dont(fd);
356 if (!udp)
357 set_tcp_nodelay(fd);
360 freeaddrinfo(ahead);
362 if (fd < 0) {
363 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
364 curve25519_free(c);
365 xfree(c);
366 fd = -1;
367 retry_server = 1;
368 closed_by_server = 0;
369 sleep(1);
370 goto retry;
373 if (!retry_server)
374 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
375 IFF_TUN | IFF_NO_PI);
377 set_nonblocking_sloppy(fd);
378 set_nonblocking_sloppy(tunfd);
380 memset(fds, 0, sizeof(fds));
381 fds[0].fd = fd;
382 fds[1].fd = tunfd;
383 fds[0].events = POLLIN;
384 fds[1].events = POLLIN;
386 buff = xmalloc_aligned(blen, 64);
388 notify_init(fd, udp, p, c, home);
390 syslog(LOG_INFO, "curvetun client ready!\n");
392 while (likely(!sigint && !closed_by_server)) {
393 poll(fds, 2, -1);
394 for (i = 0; i < 2; ++i) {
395 if ((fds[i].revents & POLLIN) != POLLIN)
396 continue;
397 if (fds[i].fd == tunfd) {
398 if (udp)
399 handler_udp_tun_to_net(tunfd, fd, p, c,
400 buff, blen);
401 else
402 handler_tcp_tun_to_net(tunfd, fd, p, c,
403 buff, blen);
404 } else if (fds[i].fd == fd) {
405 if (udp)
406 handler_udp_net_to_tun(fd, tunfd, p, c,
407 buff, blen);
408 else
409 handler_tcp_net_to_tun(fd, tunfd, p, c,
410 buff, blen);
415 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
417 if (!closed_by_server)
418 notify_close(fd);
420 xfree(buff);
421 close(fd);
422 curve25519_free(c);
423 xfree(c);
425 /* tundev still active */
426 if (closed_by_server && !sigint) {
427 syslog(LOG_ERR, "curvetun connection retry attempt!\n");
428 fd = -1;
429 retry_server = 1;
430 closed_by_server = 0;
431 sleep(1);
432 goto retry;
435 close(tunfd);
436 syslog(LOG_INFO, "curvetun client shut down!\n");
437 closelog();
439 return 0;