built_in: add kernel u* types
[netsniff-ng-old.git] / src / ct_client.c
blob7a6ae0b9db6e85a9622149322a7739bc3b75ddf6
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 "xstring.h"
33 #include "curve.h"
34 #include "mtrand.h"
35 #include "xsys.h"
36 #include "xmalloc.h"
37 #include "curvetun.h"
38 #include "ct_servmgmt.h"
39 #include "ct_usermgmt.h"
40 #include "crypto_auth_hmacsha512256.h"
42 extern volatile sig_atomic_t sigint;
43 static volatile sig_atomic_t closed_by_server = 0;
45 static void handler_udp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
46 struct curve25519_struct *c, char *buff,
47 size_t len)
49 char *cbuff;
50 ssize_t rlen, clen;
51 struct ct_proto *hdr;
52 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
54 if (!buff || len <= off)
55 return;
57 memset(buff, 0, len);
58 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
59 hdr = (struct ct_proto *) buff;
61 memset(hdr, 0, sizeof(*hdr));
62 hdr->flags = 0;
64 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
65 crypto_box_zerobytes), (rlen +
66 crypto_box_zerobytes), (unsigned char **)
67 &cbuff);
68 if (unlikely(clen <= 0))
69 goto close;
71 hdr->payload = htons((uint16_t) clen);
73 set_udp_cork(dfd);
75 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
76 write_exact(dfd, cbuff, clen, 0);
78 set_udp_uncork(dfd);
80 memset(buff, 0, len);
83 return;
84 close:
85 closed_by_server = 1;
88 static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
89 struct curve25519_struct *c, char *buff,
90 size_t len)
92 char *cbuff;
93 ssize_t rlen, err, clen;
94 struct ct_proto *hdr;
95 struct sockaddr_storage naddr;
97 socklen_t nlen = sizeof(naddr);
99 if (!buff || !len)
100 return;
102 memset(&naddr, 0, sizeof(naddr));
103 while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr,
104 &nlen)) > 0) {
105 hdr = (struct ct_proto *) buff;
107 if (unlikely(rlen < sizeof(struct ct_proto)))
108 goto close;
109 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
110 goto close;
111 if (unlikely(ntohs(hdr->payload) == 0))
112 goto close;
113 if (hdr->flags & PROTO_FLAG_EXIT)
114 goto close;
116 clen = curve25519_decode(c, p, (unsigned char *) buff +
117 sizeof(struct ct_proto),
118 rlen - sizeof(struct ct_proto),
119 (unsigned char **) &cbuff, NULL);
120 if (unlikely(clen <= 0))
121 goto close;
123 cbuff += crypto_box_zerobytes;
124 clen -= crypto_box_zerobytes;
126 err = write(dfd, cbuff, clen);
129 return;
130 close:
131 closed_by_server = 1;
134 static void handler_tcp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
135 struct curve25519_struct *c, char *buff,
136 size_t len)
138 char *cbuff;
139 ssize_t rlen, clen;
140 struct ct_proto *hdr;
141 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
143 if (!buff || len <= off)
144 return;
146 memset(buff, 0, len);
147 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
148 hdr = (struct ct_proto *) buff;
150 memset(hdr, 0, sizeof(*hdr));
151 hdr->flags = 0;
153 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
154 crypto_box_zerobytes), (rlen +
155 crypto_box_zerobytes), (unsigned char **)
156 &cbuff);
157 if (unlikely(clen <= 0))
158 goto close;
160 hdr->payload = htons((uint16_t) clen);
162 set_tcp_cork(dfd);
164 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
165 write_exact(dfd, cbuff, clen, 0);
167 set_tcp_uncork(dfd);
169 memset(buff, 0, len);
172 return;
173 close:
174 closed_by_server = 1;
177 extern ssize_t handler_tcp_read(int fd, char *buff, size_t len);
179 static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
180 struct curve25519_struct *c, char *buff,
181 size_t len)
183 char *cbuff;
184 ssize_t rlen, err, clen;
185 struct ct_proto *hdr;
187 if (!buff || !len)
188 return;
190 while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) {
191 hdr = (struct ct_proto *) buff;
193 if (unlikely(rlen < sizeof(struct ct_proto)))
194 goto close;
195 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
196 goto close;
197 if (unlikely(ntohs(hdr->payload) == 0))
198 goto close;
199 if (hdr->flags & PROTO_FLAG_EXIT)
200 goto close;
202 clen = curve25519_decode(c, p, (unsigned char *) buff +
203 sizeof(struct ct_proto),
204 rlen - sizeof(struct ct_proto),
205 (unsigned char **) &cbuff, NULL);
206 if (unlikely(clen <= 0))
207 goto close;
209 cbuff += crypto_box_zerobytes;
210 clen -= crypto_box_zerobytes;
212 err = write(dfd, cbuff, clen);
215 return;
216 close:
217 closed_by_server = 1;
220 static void notify_init(int fd, int udp, struct curve25519_proto *p,
221 struct curve25519_struct *c, char *home)
223 int fd2, i;
224 ssize_t err, clen;
225 size_t us_len, msg_len, pad;
226 struct ct_proto hdr;
227 char username[256], path[PATH_MAX], *us, *cbuff, *msg;
228 unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;
230 mt_init_by_random_device();
232 memset(&hdr, 0, sizeof(hdr));
233 hdr.flags |= PROTO_FLAG_INIT;
235 memset(path, 0, sizeof(path));
236 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
238 fd2 = open_or_die(path, O_RDONLY);
240 memset(username, 0, sizeof(username));
241 err = read(fd2, username, sizeof(username));
242 username[sizeof(username) - 1] = 0;
244 close(fd2);
246 token = get_serv_store_entry_auth_token();
247 if (!token)
248 syslog_panic("Cannot find auth token for server!\n");
250 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
251 us = xzmalloc(us_len);
253 err = username_msg(username, strlen(username) + 1,
254 us + crypto_box_zerobytes,
255 us_len - crypto_box_zerobytes);
256 if (unlikely(err))
257 syslog_panic("Cannot create init message!\n");
259 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
260 (unsigned char **) &cbuff);
261 if (unlikely(clen <= 0))
262 syslog_panic("Init encrypt error!\n");
264 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
265 if (unlikely(err))
266 syslog_panic("Cannot create init hmac message!\n");
268 pad = mt_rand_int32() % 200;
269 msg_len = clen + sizeof(auth) + pad;
271 msg = xzmalloc(msg_len);
272 memcpy(msg, auth, sizeof(auth));
273 memcpy(msg + sizeof(auth), cbuff, clen);
275 for (i = sizeof(auth) + clen; i < msg_len; ++i)
276 msg[i] = (uint8_t) mt_rand_int32();
278 hdr.payload = htons((uint16_t) msg_len);
280 set_sock_cork(fd, udp);
282 write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
283 write_exact(fd, msg, msg_len, 0);
285 set_sock_uncork(fd, udp);
287 xfree(msg);
288 xfree(us);
291 static void notify_close(int fd)
293 struct ct_proto hdr;
295 memset(&hdr, 0, sizeof(hdr));
297 hdr.flags |= PROTO_FLAG_EXIT;
298 hdr.payload = 0;
300 write_exact(fd, &hdr, sizeof(hdr), 0);
303 int client_main(char *home, char *dev, char *host, char *port, int udp)
305 int fd = -1, tunfd = 0, retry_server = 0;
306 int ret, try = 1, i;
307 struct addrinfo hints, *ahead, *ai;
308 struct sockaddr_in6 *saddr6;
309 struct pollfd fds[2];
310 struct curve25519_proto *p;
311 struct curve25519_struct *c;
312 char *buff;
313 size_t blen = TUNBUFF_SIZ; //FIXME
315 retry:
316 if (!retry_server) {
317 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
318 syslog(LOG_INFO, "curvetun client booting!\n");
321 c = xmalloc(sizeof(struct curve25519_struct));
323 ret = curve25519_alloc_or_maybe_die(c);
324 if (ret < 0)
325 syslog_panic("Cannot init curve!\n");
327 p = get_serv_store_entry_proto_inf();
328 if (!p)
329 syslog_panic("Cannot proto!\n");
331 memset(&hints, 0, sizeof(hints));
332 hints.ai_family = PF_UNSPEC;
333 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
334 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
335 hints.ai_flags = AI_NUMERICSERV;
337 ret = getaddrinfo(host, port, &hints, &ahead);
338 if (ret < 0) {
339 syslog(LOG_ERR, "Cannot get address info! Retry!\n");
340 curve25519_free(c);
341 xfree(c);
342 fd = -1;
343 retry_server = 1;
344 closed_by_server = 0;
345 sleep(1);
346 goto retry;
349 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
350 if (ai->ai_family == PF_INET6)
351 saddr6 = (struct sockaddr_in6 *) ai->ai_addr;
352 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
353 if (fd < 0)
354 continue;
355 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
356 if (ret < 0) {
357 syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
358 try++, strerror(errno));
359 close(fd);
360 fd = -1;
361 continue;
364 set_socket_keepalive(fd);
365 set_mtu_disc_dont(fd);
366 if (!udp)
367 set_tcp_nodelay(fd);
370 freeaddrinfo(ahead);
372 if (fd < 0) {
373 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
374 curve25519_free(c);
375 xfree(c);
376 fd = -1;
377 retry_server = 1;
378 closed_by_server = 0;
379 sleep(1);
380 goto retry;
383 if (!retry_server)
384 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
385 IFF_TUN | IFF_NO_PI);
387 set_nonblocking_sloppy(fd);
388 set_nonblocking_sloppy(tunfd);
390 memset(fds, 0, sizeof(fds));
391 fds[0].fd = fd;
392 fds[1].fd = tunfd;
393 fds[0].events = POLLIN;
394 fds[1].events = POLLIN;
396 buff = xmalloc_aligned(blen, 64);
398 notify_init(fd, udp, p, c, home);
400 syslog(LOG_INFO, "curvetun client ready!\n");
402 while (likely(!sigint && !closed_by_server)) {
403 poll(fds, 2, -1);
404 for (i = 0; i < 2; ++i) {
405 if ((fds[i].revents & POLLIN) != POLLIN)
406 continue;
407 if (fds[i].fd == tunfd) {
408 if (udp)
409 handler_udp_tun_to_net(tunfd, fd, p, c,
410 buff, blen);
411 else
412 handler_tcp_tun_to_net(tunfd, fd, p, c,
413 buff, blen);
414 } else if (fds[i].fd == fd) {
415 if (udp)
416 handler_udp_net_to_tun(fd, tunfd, p, c,
417 buff, blen);
418 else
419 handler_tcp_net_to_tun(fd, tunfd, p, c,
420 buff, blen);
425 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
427 if (!closed_by_server)
428 notify_close(fd);
430 xfree(buff);
431 close(fd);
432 curve25519_free(c);
433 xfree(c);
435 /* tundev still active */
436 if (closed_by_server && !sigint) {
437 syslog(LOG_ERR, "curvetun connection retry attempt!\n");
438 fd = -1;
439 retry_server = 1;
440 closed_by_server = 0;
441 sleep(1);
442 goto retry;
445 close(tunfd);
446 syslog(LOG_INFO, "curvetun client shut down!\n");
447 closelog();
449 return 0;