docs: moved manpages to man, remove talks from repo
[netsniff-ng.git] / ct_client.c
blob93f67afa2557dc4bc37d94eebd9678cefe40f570
1 /*
2 * curvetun - the cipherspace wormhole creator
3 * Part of the netsniff-ng project
4 * By Daniel Borkmann <daniel@netsniff-ng.org>
5 * Copyright 2011 Daniel Borkmann <daniel@netsniff-ng.org>,
6 * Subject to the GPL, version 2.
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <netdb.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include <syslog.h>
17 #include <limits.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
24 #include <sys/poll.h>
25 #include <netinet/tcp.h>
26 #include <netinet/udp.h>
27 #include <linux/if_tun.h>
29 #include "built_in.h"
30 #include "die.h"
31 #include "xio.h"
32 #include "xutils.h"
33 #include "curve.h"
34 #include "xmalloc.h"
35 #include "curvetun.h"
36 #include "ct_servmgmt.h"
37 #include "ct_usermgmt.h"
38 #include "crypto_auth_hmacsha512256.h"
40 extern volatile sig_atomic_t sigint;
41 static volatile sig_atomic_t closed_by_server = 0;
43 static void handler_udp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
44 struct curve25519_struct *c, char *buff,
45 size_t len)
47 char *cbuff;
48 ssize_t rlen, clen;
49 struct ct_proto *hdr;
50 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
52 if (!buff || len <= off)
53 return;
55 memset(buff, 0, len);
56 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
57 hdr = (struct ct_proto *) buff;
59 memset(hdr, 0, sizeof(*hdr));
60 hdr->flags = 0;
62 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
63 crypto_box_zerobytes), (rlen +
64 crypto_box_zerobytes), (unsigned char **)
65 &cbuff);
66 if (unlikely(clen <= 0))
67 goto close;
69 hdr->payload = htons((uint16_t) clen);
71 set_udp_cork(dfd);
73 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
74 write_exact(dfd, cbuff, clen, 0);
76 set_udp_uncork(dfd);
78 memset(buff, 0, len);
81 return;
82 close:
83 closed_by_server = 1;
86 static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
87 struct curve25519_struct *c, char *buff,
88 size_t len)
90 char *cbuff;
91 ssize_t rlen, clen;
92 struct ct_proto *hdr;
93 struct sockaddr_storage naddr;
95 socklen_t nlen = sizeof(naddr);
97 if (!buff || !len)
98 return;
100 memset(&naddr, 0, sizeof(naddr));
101 while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr,
102 &nlen)) > 0) {
103 hdr = (struct ct_proto *) buff;
105 if (unlikely(rlen < sizeof(struct ct_proto)))
106 goto close;
107 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
108 goto close;
109 if (unlikely(ntohs(hdr->payload) == 0))
110 goto close;
111 if (hdr->flags & PROTO_FLAG_EXIT)
112 goto close;
114 clen = curve25519_decode(c, p, (unsigned char *) buff +
115 sizeof(struct ct_proto),
116 rlen - sizeof(struct ct_proto),
117 (unsigned char **) &cbuff, NULL);
118 if (unlikely(clen <= 0))
119 goto close;
121 cbuff += crypto_box_zerobytes;
122 clen -= crypto_box_zerobytes;
124 if (write(dfd, cbuff, clen)) { ; }
127 return;
128 close:
129 closed_by_server = 1;
132 static void handler_tcp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
133 struct curve25519_struct *c, char *buff,
134 size_t len)
136 char *cbuff;
137 ssize_t rlen, clen;
138 struct ct_proto *hdr;
139 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
141 if (!buff || len <= off)
142 return;
144 memset(buff, 0, len);
145 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
146 hdr = (struct ct_proto *) buff;
148 memset(hdr, 0, sizeof(*hdr));
149 hdr->flags = 0;
151 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
152 crypto_box_zerobytes), (rlen +
153 crypto_box_zerobytes), (unsigned char **)
154 &cbuff);
155 if (unlikely(clen <= 0))
156 goto close;
158 hdr->payload = htons((uint16_t) clen);
160 set_tcp_cork(dfd);
162 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
163 write_exact(dfd, cbuff, clen, 0);
165 set_tcp_uncork(dfd);
167 memset(buff, 0, len);
170 return;
171 close:
172 closed_by_server = 1;
175 extern ssize_t handler_tcp_read(int fd, char *buff, size_t len);
177 static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
178 struct curve25519_struct *c, char *buff,
179 size_t len)
181 char *cbuff;
182 ssize_t rlen, clen;
183 struct ct_proto *hdr;
185 if (!buff || !len)
186 return;
188 while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) {
189 hdr = (struct ct_proto *) buff;
191 if (unlikely(rlen < sizeof(struct ct_proto)))
192 goto close;
193 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
194 goto close;
195 if (unlikely(ntohs(hdr->payload) == 0))
196 goto close;
197 if (hdr->flags & PROTO_FLAG_EXIT)
198 goto close;
200 clen = curve25519_decode(c, p, (unsigned char *) buff +
201 sizeof(struct ct_proto),
202 rlen - sizeof(struct ct_proto),
203 (unsigned char **) &cbuff, NULL);
204 if (unlikely(clen <= 0))
205 goto close;
207 cbuff += crypto_box_zerobytes;
208 clen -= crypto_box_zerobytes;
210 if (write(dfd, cbuff, clen)) { ; }
213 return;
214 close:
215 closed_by_server = 1;
218 static void notify_init(int fd, int udp, struct curve25519_proto *p,
219 struct curve25519_struct *c, char *home)
221 int fd2, i;
222 ssize_t err, clen;
223 size_t us_len, msg_len, pad;
224 struct ct_proto hdr;
225 char username[256], path[PATH_MAX], *us, *cbuff, *msg;
226 unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;
228 memset(&hdr, 0, sizeof(hdr));
229 hdr.flags |= PROTO_FLAG_INIT;
231 memset(path, 0, sizeof(path));
232 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
234 fd2 = open_or_die(path, O_RDONLY);
236 memset(username, 0, sizeof(username));
237 err = read(fd2, username, sizeof(username));
238 username[sizeof(username) - 1] = 0;
240 close(fd2);
242 token = get_serv_store_entry_auth_token();
243 if (!token)
244 syslog_panic("Cannot find auth token for server!\n");
246 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
247 us = xzmalloc(us_len);
249 err = username_msg(username, strlen(username) + 1,
250 us + crypto_box_zerobytes,
251 us_len - crypto_box_zerobytes);
252 if (unlikely(err))
253 syslog_panic("Cannot create init message!\n");
255 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
256 (unsigned char **) &cbuff);
257 if (unlikely(clen <= 0))
258 syslog_panic("Init encrypt error!\n");
260 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
261 if (unlikely(err))
262 syslog_panic("Cannot create init hmac message!\n");
264 pad = secrand() % 200;
265 msg_len = clen + sizeof(auth) + pad;
267 msg = xzmalloc(msg_len);
268 memcpy(msg, auth, sizeof(auth));
269 memcpy(msg + sizeof(auth), cbuff, clen);
271 for (i = sizeof(auth) + clen; i < msg_len; ++i)
272 msg[i] = (uint8_t) secrand();
274 hdr.payload = htons((uint16_t) msg_len);
276 set_sock_cork(fd, udp);
278 write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
279 write_exact(fd, msg, msg_len, 0);
281 set_sock_uncork(fd, udp);
283 xfree(msg);
284 xfree(us);
287 static void notify_close(int fd)
289 struct ct_proto hdr;
291 memset(&hdr, 0, sizeof(hdr));
293 hdr.flags |= PROTO_FLAG_EXIT;
294 hdr.payload = 0;
296 write_exact(fd, &hdr, sizeof(hdr), 0);
299 int client_main(char *home, char *dev, char *host, char *port, int udp)
301 int fd = -1, tunfd = 0, retry_server = 0;
302 int ret, try = 1, i;
303 struct addrinfo hints, *ahead, *ai;
304 struct pollfd fds[2];
305 struct curve25519_proto *p;
306 struct curve25519_struct *c;
307 char *buff;
308 size_t blen = TUNBUFF_SIZ; //FIXME
310 retry:
311 if (!retry_server) {
312 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
313 syslog(LOG_INFO, "curvetun client booting!\n");
316 c = xmalloc(sizeof(struct curve25519_struct));
318 curve25519_alloc_or_maybe_die(c);
320 p = get_serv_store_entry_proto_inf();
321 if (!p)
322 syslog_panic("Cannot proto!\n");
324 memset(&hints, 0, sizeof(hints));
325 hints.ai_family = PF_UNSPEC;
326 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
327 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
328 hints.ai_flags = AI_NUMERICSERV;
330 ret = getaddrinfo(host, port, &hints, &ahead);
331 if (ret < 0) {
332 syslog(LOG_ERR, "Cannot get address info! Retry!\n");
333 curve25519_free(c);
334 xfree(c);
335 fd = -1;
336 retry_server = 1;
337 closed_by_server = 0;
338 sleep(1);
339 goto retry;
342 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
343 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
344 if (fd < 0)
345 continue;
346 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
347 if (ret < 0) {
348 syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
349 try++, strerror(errno));
350 close(fd);
351 fd = -1;
352 continue;
355 set_socket_keepalive(fd);
356 set_mtu_disc_dont(fd);
357 if (!udp)
358 set_tcp_nodelay(fd);
361 freeaddrinfo(ahead);
363 if (fd < 0) {
364 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
365 curve25519_free(c);
366 xfree(c);
367 fd = -1;
368 retry_server = 1;
369 closed_by_server = 0;
370 sleep(1);
371 goto retry;
374 if (!retry_server)
375 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
376 IFF_TUN | IFF_NO_PI);
378 set_nonblocking_sloppy(fd);
379 set_nonblocking_sloppy(tunfd);
381 memset(fds, 0, sizeof(fds));
382 fds[0].fd = fd;
383 fds[1].fd = tunfd;
384 fds[0].events = POLLIN;
385 fds[1].events = POLLIN;
387 buff = xmalloc_aligned(blen, 64);
389 notify_init(fd, udp, p, c, home);
391 syslog(LOG_INFO, "curvetun client ready!\n");
393 while (likely(!sigint && !closed_by_server)) {
394 poll(fds, 2, -1);
395 for (i = 0; i < 2; ++i) {
396 if ((fds[i].revents & POLLIN) != POLLIN)
397 continue;
398 if (fds[i].fd == tunfd) {
399 if (udp)
400 handler_udp_tun_to_net(tunfd, fd, p, c,
401 buff, blen);
402 else
403 handler_tcp_tun_to_net(tunfd, fd, p, c,
404 buff, blen);
405 } else if (fds[i].fd == fd) {
406 if (udp)
407 handler_udp_net_to_tun(fd, tunfd, p, c,
408 buff, blen);
409 else
410 handler_tcp_net_to_tun(fd, tunfd, p, c,
411 buff, blen);
416 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
418 if (!closed_by_server)
419 notify_close(fd);
421 xfree(buff);
422 close(fd);
423 curve25519_free(c);
424 xfree(c);
426 /* tundev still active */
427 if (closed_by_server && !sigint) {
428 syslog(LOG_ERR, "curvetun connection retry attempt!\n");
429 fd = -1;
430 retry_server = 1;
431 closed_by_server = 0;
432 sleep(1);
433 goto retry;
436 close(tunfd);
437 syslog(LOG_INFO, "curvetun client shut down!\n");
438 closelog();
440 return 0;