sig: add signal handling functions
[netsniff-ng.git] / ct_client.c
blob50f5df4f390483adcd3d9e3a3f5d5350cfd0eafa
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 "str.h"
31 #include "sock.h"
32 #include "ioops.h"
33 #include "xutils.h"
34 #include "curve.h"
35 #include "xmalloc.h"
36 #include "corking.h"
37 #include "ioexact.h"
38 #include "curvetun.h"
39 #include "ct_servmgmt.h"
40 #include "ct_usermgmt.h"
41 #include "crypto_auth_hmacsha512256.h"
43 extern volatile sig_atomic_t sigint;
44 static volatile sig_atomic_t closed_by_server = 0;
46 static void handler_udp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
47 struct curve25519_struct *c, char *buff,
48 size_t len)
50 char *cbuff;
51 ssize_t rlen, clen;
52 struct ct_proto *hdr;
53 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
55 if (!buff || len <= off)
56 return;
58 memset(buff, 0, len);
59 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
60 hdr = (struct ct_proto *) buff;
62 memset(hdr, 0, sizeof(*hdr));
63 hdr->flags = 0;
65 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
66 crypto_box_zerobytes), (rlen +
67 crypto_box_zerobytes), (unsigned char **)
68 &cbuff);
69 if (unlikely(clen <= 0))
70 goto close;
72 hdr->payload = htons((uint16_t) clen);
74 set_udp_cork(dfd);
76 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
77 write_exact(dfd, cbuff, clen, 0);
79 set_udp_uncork(dfd);
81 memset(buff, 0, len);
84 return;
85 close:
86 closed_by_server = 1;
89 static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
90 struct curve25519_struct *c, char *buff,
91 size_t len)
93 char *cbuff;
94 ssize_t rlen, clen;
95 struct ct_proto *hdr;
96 struct sockaddr_storage naddr;
98 socklen_t nlen = sizeof(naddr);
100 if (!buff || !len)
101 return;
103 memset(&naddr, 0, sizeof(naddr));
104 while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr,
105 &nlen)) > 0) {
106 hdr = (struct ct_proto *) buff;
108 if (unlikely(rlen < sizeof(struct ct_proto)))
109 goto close;
110 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
111 goto close;
112 if (unlikely(ntohs(hdr->payload) == 0))
113 goto close;
114 if (hdr->flags & PROTO_FLAG_EXIT)
115 goto close;
117 clen = curve25519_decode(c, p, (unsigned char *) buff +
118 sizeof(struct ct_proto),
119 rlen - sizeof(struct ct_proto),
120 (unsigned char **) &cbuff, NULL);
121 if (unlikely(clen <= 0))
122 goto close;
124 cbuff += crypto_box_zerobytes;
125 clen -= crypto_box_zerobytes;
127 if (write(dfd, cbuff, clen)) { ; }
130 return;
131 close:
132 closed_by_server = 1;
135 static void handler_tcp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
136 struct curve25519_struct *c, char *buff,
137 size_t len)
139 char *cbuff;
140 ssize_t rlen, clen;
141 struct ct_proto *hdr;
142 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
144 if (!buff || len <= off)
145 return;
147 memset(buff, 0, len);
148 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
149 hdr = (struct ct_proto *) buff;
151 memset(hdr, 0, sizeof(*hdr));
152 hdr->flags = 0;
154 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
155 crypto_box_zerobytes), (rlen +
156 crypto_box_zerobytes), (unsigned char **)
157 &cbuff);
158 if (unlikely(clen <= 0))
159 goto close;
161 hdr->payload = htons((uint16_t) clen);
163 set_tcp_cork(dfd);
165 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
166 write_exact(dfd, cbuff, clen, 0);
168 set_tcp_uncork(dfd);
170 memset(buff, 0, len);
173 return;
174 close:
175 closed_by_server = 1;
178 extern ssize_t handler_tcp_read(int fd, char *buff, size_t len);
180 static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
181 struct curve25519_struct *c, char *buff,
182 size_t len)
184 char *cbuff;
185 ssize_t rlen, clen;
186 struct ct_proto *hdr;
188 if (!buff || !len)
189 return;
191 while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) {
192 hdr = (struct ct_proto *) buff;
194 if (unlikely(rlen < sizeof(struct ct_proto)))
195 goto close;
196 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
197 goto close;
198 if (unlikely(ntohs(hdr->payload) == 0))
199 goto close;
200 if (hdr->flags & PROTO_FLAG_EXIT)
201 goto close;
203 clen = curve25519_decode(c, p, (unsigned char *) buff +
204 sizeof(struct ct_proto),
205 rlen - sizeof(struct ct_proto),
206 (unsigned char **) &cbuff, NULL);
207 if (unlikely(clen <= 0))
208 goto close;
210 cbuff += crypto_box_zerobytes;
211 clen -= crypto_box_zerobytes;
213 if (write(dfd, cbuff, clen)) { ; }
216 return;
217 close:
218 closed_by_server = 1;
221 static void notify_init(int fd, int udp, struct curve25519_proto *p,
222 struct curve25519_struct *c, char *home)
224 int fd2, i;
225 ssize_t err, clen;
226 size_t us_len, msg_len, pad;
227 struct ct_proto hdr;
228 char username[256], path[PATH_MAX], *us, *cbuff, *msg;
229 unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;
231 memset(&hdr, 0, sizeof(hdr));
232 hdr.flags |= PROTO_FLAG_INIT;
234 memset(path, 0, sizeof(path));
235 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
237 fd2 = open_or_die(path, O_RDONLY);
239 memset(username, 0, sizeof(username));
240 err = read(fd2, username, sizeof(username));
241 username[sizeof(username) - 1] = 0;
243 close(fd2);
245 token = get_serv_store_entry_auth_token();
246 if (!token)
247 syslog_panic("Cannot find auth token for server!\n");
249 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
250 us = xzmalloc(us_len);
252 err = username_msg(username, strlen(username) + 1,
253 us + crypto_box_zerobytes,
254 us_len - crypto_box_zerobytes);
255 if (unlikely(err))
256 syslog_panic("Cannot create init message!\n");
258 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
259 (unsigned char **) &cbuff);
260 if (unlikely(clen <= 0))
261 syslog_panic("Init encrypt error!\n");
263 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
264 if (unlikely(err))
265 syslog_panic("Cannot create init hmac message!\n");
267 pad = ((uint32_t) secrand()) % 200;
268 msg_len = clen + sizeof(auth) + pad;
270 msg = xzmalloc(msg_len);
271 memcpy(msg, auth, sizeof(auth));
272 memcpy(msg + sizeof(auth), cbuff, clen);
274 for (i = sizeof(auth) + clen; i < msg_len; ++i)
275 msg[i] = (uint8_t) secrand();
277 hdr.payload = htons((uint16_t) msg_len);
279 set_sock_cork(fd, udp);
281 write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
282 write_exact(fd, msg, msg_len, 0);
284 set_sock_uncork(fd, udp);
286 xfree(msg);
287 xfree(us);
290 static void notify_close(int fd)
292 struct ct_proto hdr;
294 memset(&hdr, 0, sizeof(hdr));
296 hdr.flags |= PROTO_FLAG_EXIT;
297 hdr.payload = 0;
299 write_exact(fd, &hdr, sizeof(hdr), 0);
302 int client_main(char *home, char *dev, char *host, char *port, int udp)
304 int fd = -1, tunfd = 0, retry_server = 0;
305 int ret, try = 1, i;
306 struct addrinfo hints, *ahead, *ai;
307 struct pollfd fds[2];
308 struct curve25519_proto *p;
309 struct curve25519_struct *c;
310 char *buff;
311 size_t blen = TUNBUFF_SIZ; //FIXME
313 retry:
314 if (!retry_server) {
315 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
316 syslog(LOG_INFO, "curvetun client booting!\n");
319 c = xmalloc(sizeof(struct curve25519_struct));
321 curve25519_alloc_or_maybe_die(c);
323 p = get_serv_store_entry_proto_inf();
324 if (!p)
325 syslog_panic("Cannot proto!\n");
327 memset(&hints, 0, sizeof(hints));
328 hints.ai_family = PF_UNSPEC;
329 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
330 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
331 hints.ai_flags = AI_NUMERICSERV;
333 ret = getaddrinfo(host, port, &hints, &ahead);
334 if (ret < 0) {
335 syslog(LOG_ERR, "Cannot get address info! Retry!\n");
336 curve25519_free(c);
337 xfree(c);
338 fd = -1;
339 retry_server = 1;
340 closed_by_server = 0;
341 sleep(1);
342 goto retry;
345 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
346 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
347 if (fd < 0)
348 continue;
349 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
350 if (ret < 0) {
351 syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
352 try++, strerror(errno));
353 close(fd);
354 fd = -1;
355 continue;
358 set_socket_keepalive(fd);
359 set_mtu_disc_dont(fd);
360 if (!udp)
361 set_tcp_nodelay(fd);
364 freeaddrinfo(ahead);
366 if (fd < 0) {
367 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
368 curve25519_free(c);
369 xfree(c);
370 fd = -1;
371 retry_server = 1;
372 closed_by_server = 0;
373 sleep(1);
374 goto retry;
377 if (!retry_server)
378 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
379 IFF_TUN | IFF_NO_PI);
381 set_nonblocking_sloppy(fd);
382 set_nonblocking_sloppy(tunfd);
384 memset(fds, 0, sizeof(fds));
385 fds[0].fd = fd;
386 fds[1].fd = tunfd;
387 fds[0].events = POLLIN;
388 fds[1].events = POLLIN;
390 buff = xmalloc_aligned(blen, 64);
392 notify_init(fd, udp, p, c, home);
394 syslog(LOG_INFO, "curvetun client ready!\n");
396 while (likely(!sigint && !closed_by_server)) {
397 poll(fds, 2, -1);
398 for (i = 0; i < 2; ++i) {
399 if ((fds[i].revents & POLLIN) != POLLIN)
400 continue;
401 if (fds[i].fd == tunfd) {
402 if (udp)
403 handler_udp_tun_to_net(tunfd, fd, p, c,
404 buff, blen);
405 else
406 handler_tcp_tun_to_net(tunfd, fd, p, c,
407 buff, blen);
408 } else if (fds[i].fd == fd) {
409 if (udp)
410 handler_udp_net_to_tun(fd, tunfd, p, c,
411 buff, blen);
412 else
413 handler_tcp_net_to_tun(fd, tunfd, p, c,
414 buff, blen);
419 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
421 if (!closed_by_server)
422 notify_close(fd);
424 xfree(buff);
425 close(fd);
426 curve25519_free(c);
427 xfree(c);
429 /* tundev still active */
430 if (closed_by_server && !sigint) {
431 syslog(LOG_ERR, "curvetun connection retry attempt!\n");
432 fd = -1;
433 retry_server = 1;
434 closed_by_server = 0;
435 sleep(1);
436 goto retry;
439 close(tunfd);
440 syslog(LOG_INFO, "curvetun client shut down!\n");
441 closelog();
443 return 0;