corking: break out udp/tcp cork functions
[netsniff-ng.git] / ct_client.c
blobf51371fd72c59ade5b70b49d5e32212f7511e160
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 "xio.h"
32 #include "xutils.h"
33 #include "curve.h"
34 #include "xmalloc.h"
35 #include "corking.h"
36 #include "curvetun.h"
37 #include "ct_servmgmt.h"
38 #include "ct_usermgmt.h"
39 #include "crypto_auth_hmacsha512256.h"
41 extern volatile sig_atomic_t sigint;
42 static volatile sig_atomic_t closed_by_server = 0;
44 static void handler_udp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
45 struct curve25519_struct *c, char *buff,
46 size_t len)
48 char *cbuff;
49 ssize_t rlen, clen;
50 struct ct_proto *hdr;
51 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
53 if (!buff || len <= off)
54 return;
56 memset(buff, 0, len);
57 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
58 hdr = (struct ct_proto *) buff;
60 memset(hdr, 0, sizeof(*hdr));
61 hdr->flags = 0;
63 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
64 crypto_box_zerobytes), (rlen +
65 crypto_box_zerobytes), (unsigned char **)
66 &cbuff);
67 if (unlikely(clen <= 0))
68 goto close;
70 hdr->payload = htons((uint16_t) clen);
72 set_udp_cork(dfd);
74 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
75 write_exact(dfd, cbuff, clen, 0);
77 set_udp_uncork(dfd);
79 memset(buff, 0, len);
82 return;
83 close:
84 closed_by_server = 1;
87 static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
88 struct curve25519_struct *c, char *buff,
89 size_t len)
91 char *cbuff;
92 ssize_t rlen, clen;
93 struct ct_proto *hdr;
94 struct sockaddr_storage naddr;
96 socklen_t nlen = sizeof(naddr);
98 if (!buff || !len)
99 return;
101 memset(&naddr, 0, sizeof(naddr));
102 while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr,
103 &nlen)) > 0) {
104 hdr = (struct ct_proto *) buff;
106 if (unlikely(rlen < sizeof(struct ct_proto)))
107 goto close;
108 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
109 goto close;
110 if (unlikely(ntohs(hdr->payload) == 0))
111 goto close;
112 if (hdr->flags & PROTO_FLAG_EXIT)
113 goto close;
115 clen = curve25519_decode(c, p, (unsigned char *) buff +
116 sizeof(struct ct_proto),
117 rlen - sizeof(struct ct_proto),
118 (unsigned char **) &cbuff, NULL);
119 if (unlikely(clen <= 0))
120 goto close;
122 cbuff += crypto_box_zerobytes;
123 clen -= crypto_box_zerobytes;
125 if (write(dfd, cbuff, clen)) { ; }
128 return;
129 close:
130 closed_by_server = 1;
133 static void handler_tcp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
134 struct curve25519_struct *c, char *buff,
135 size_t len)
137 char *cbuff;
138 ssize_t rlen, clen;
139 struct ct_proto *hdr;
140 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
142 if (!buff || len <= off)
143 return;
145 memset(buff, 0, len);
146 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
147 hdr = (struct ct_proto *) buff;
149 memset(hdr, 0, sizeof(*hdr));
150 hdr->flags = 0;
152 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
153 crypto_box_zerobytes), (rlen +
154 crypto_box_zerobytes), (unsigned char **)
155 &cbuff);
156 if (unlikely(clen <= 0))
157 goto close;
159 hdr->payload = htons((uint16_t) clen);
161 set_tcp_cork(dfd);
163 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
164 write_exact(dfd, cbuff, clen, 0);
166 set_tcp_uncork(dfd);
168 memset(buff, 0, len);
171 return;
172 close:
173 closed_by_server = 1;
176 extern ssize_t handler_tcp_read(int fd, char *buff, size_t len);
178 static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
179 struct curve25519_struct *c, char *buff,
180 size_t len)
182 char *cbuff;
183 ssize_t rlen, clen;
184 struct ct_proto *hdr;
186 if (!buff || !len)
187 return;
189 while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) {
190 hdr = (struct ct_proto *) buff;
192 if (unlikely(rlen < sizeof(struct ct_proto)))
193 goto close;
194 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
195 goto close;
196 if (unlikely(ntohs(hdr->payload) == 0))
197 goto close;
198 if (hdr->flags & PROTO_FLAG_EXIT)
199 goto close;
201 clen = curve25519_decode(c, p, (unsigned char *) buff +
202 sizeof(struct ct_proto),
203 rlen - sizeof(struct ct_proto),
204 (unsigned char **) &cbuff, NULL);
205 if (unlikely(clen <= 0))
206 goto close;
208 cbuff += crypto_box_zerobytes;
209 clen -= crypto_box_zerobytes;
211 if (write(dfd, cbuff, clen)) { ; }
214 return;
215 close:
216 closed_by_server = 1;
219 static void notify_init(int fd, int udp, struct curve25519_proto *p,
220 struct curve25519_struct *c, char *home)
222 int fd2, i;
223 ssize_t err, clen;
224 size_t us_len, msg_len, pad;
225 struct ct_proto hdr;
226 char username[256], path[PATH_MAX], *us, *cbuff, *msg;
227 unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;
229 memset(&hdr, 0, sizeof(hdr));
230 hdr.flags |= PROTO_FLAG_INIT;
232 memset(path, 0, sizeof(path));
233 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
235 fd2 = open_or_die(path, O_RDONLY);
237 memset(username, 0, sizeof(username));
238 err = read(fd2, username, sizeof(username));
239 username[sizeof(username) - 1] = 0;
241 close(fd2);
243 token = get_serv_store_entry_auth_token();
244 if (!token)
245 syslog_panic("Cannot find auth token for server!\n");
247 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
248 us = xzmalloc(us_len);
250 err = username_msg(username, strlen(username) + 1,
251 us + crypto_box_zerobytes,
252 us_len - crypto_box_zerobytes);
253 if (unlikely(err))
254 syslog_panic("Cannot create init message!\n");
256 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
257 (unsigned char **) &cbuff);
258 if (unlikely(clen <= 0))
259 syslog_panic("Init encrypt error!\n");
261 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
262 if (unlikely(err))
263 syslog_panic("Cannot create init hmac message!\n");
265 pad = ((uint32_t) secrand()) % 200;
266 msg_len = clen + sizeof(auth) + pad;
268 msg = xzmalloc(msg_len);
269 memcpy(msg, auth, sizeof(auth));
270 memcpy(msg + sizeof(auth), cbuff, clen);
272 for (i = sizeof(auth) + clen; i < msg_len; ++i)
273 msg[i] = (uint8_t) secrand();
275 hdr.payload = htons((uint16_t) msg_len);
277 set_sock_cork(fd, udp);
279 write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
280 write_exact(fd, msg, msg_len, 0);
282 set_sock_uncork(fd, udp);
284 xfree(msg);
285 xfree(us);
288 static void notify_close(int fd)
290 struct ct_proto hdr;
292 memset(&hdr, 0, sizeof(hdr));
294 hdr.flags |= PROTO_FLAG_EXIT;
295 hdr.payload = 0;
297 write_exact(fd, &hdr, sizeof(hdr), 0);
300 int client_main(char *home, char *dev, char *host, char *port, int udp)
302 int fd = -1, tunfd = 0, retry_server = 0;
303 int ret, try = 1, i;
304 struct addrinfo hints, *ahead, *ai;
305 struct pollfd fds[2];
306 struct curve25519_proto *p;
307 struct curve25519_struct *c;
308 char *buff;
309 size_t blen = TUNBUFF_SIZ; //FIXME
311 retry:
312 if (!retry_server) {
313 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
314 syslog(LOG_INFO, "curvetun client booting!\n");
317 c = xmalloc(sizeof(struct curve25519_struct));
319 curve25519_alloc_or_maybe_die(c);
321 p = get_serv_store_entry_proto_inf();
322 if (!p)
323 syslog_panic("Cannot proto!\n");
325 memset(&hints, 0, sizeof(hints));
326 hints.ai_family = PF_UNSPEC;
327 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
328 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
329 hints.ai_flags = AI_NUMERICSERV;
331 ret = getaddrinfo(host, port, &hints, &ahead);
332 if (ret < 0) {
333 syslog(LOG_ERR, "Cannot get address info! Retry!\n");
334 curve25519_free(c);
335 xfree(c);
336 fd = -1;
337 retry_server = 1;
338 closed_by_server = 0;
339 sleep(1);
340 goto retry;
343 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
344 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
345 if (fd < 0)
346 continue;
347 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
348 if (ret < 0) {
349 syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
350 try++, strerror(errno));
351 close(fd);
352 fd = -1;
353 continue;
356 set_socket_keepalive(fd);
357 set_mtu_disc_dont(fd);
358 if (!udp)
359 set_tcp_nodelay(fd);
362 freeaddrinfo(ahead);
364 if (fd < 0) {
365 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
366 curve25519_free(c);
367 xfree(c);
368 fd = -1;
369 retry_server = 1;
370 closed_by_server = 0;
371 sleep(1);
372 goto retry;
375 if (!retry_server)
376 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
377 IFF_TUN | IFF_NO_PI);
379 set_nonblocking_sloppy(fd);
380 set_nonblocking_sloppy(tunfd);
382 memset(fds, 0, sizeof(fds));
383 fds[0].fd = fd;
384 fds[1].fd = tunfd;
385 fds[0].events = POLLIN;
386 fds[1].events = POLLIN;
388 buff = xmalloc_aligned(blen, 64);
390 notify_init(fd, udp, p, c, home);
392 syslog(LOG_INFO, "curvetun client ready!\n");
394 while (likely(!sigint && !closed_by_server)) {
395 poll(fds, 2, -1);
396 for (i = 0; i < 2; ++i) {
397 if ((fds[i].revents & POLLIN) != POLLIN)
398 continue;
399 if (fds[i].fd == tunfd) {
400 if (udp)
401 handler_udp_tun_to_net(tunfd, fd, p, c,
402 buff, blen);
403 else
404 handler_tcp_tun_to_net(tunfd, fd, p, c,
405 buff, blen);
406 } else if (fds[i].fd == fd) {
407 if (udp)
408 handler_udp_net_to_tun(fd, tunfd, p, c,
409 buff, blen);
410 else
411 handler_tcp_net_to_tun(fd, tunfd, p, c,
412 buff, blen);
417 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
419 if (!closed_by_server)
420 notify_close(fd);
422 xfree(buff);
423 close(fd);
424 curve25519_free(c);
425 xfree(c);
427 /* tundev still active */
428 if (closed_by_server && !sigint) {
429 syslog(LOG_ERR, "curvetun connection retry attempt!\n");
430 fd = -1;
431 retry_server = 1;
432 closed_by_server = 0;
433 sleep(1);
434 goto retry;
437 close(tunfd);
438 syslog(LOG_INFO, "curvetun client shut down!\n");
439 closelog();
441 return 0;