dissector: explicitly init array
[netsniff-ng.git] / ct_client.c
blob37b6090d54f01d7b72b948f7a4ee3330683f9b15
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 "curve.h"
34 #include "xmalloc.h"
35 #include "corking.h"
36 #include "ioexact.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, 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 if (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, 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 if (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 memset(&hdr, 0, sizeof(hdr));
231 hdr.flags |= PROTO_FLAG_INIT;
233 memset(path, 0, sizeof(path));
234 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
236 fd2 = open_or_die(path, O_RDONLY);
238 memset(username, 0, sizeof(username));
239 err = read(fd2, username, sizeof(username));
240 username[sizeof(username) - 1] = 0;
242 close(fd2);
244 token = get_serv_store_entry_auth_token();
245 if (!token)
246 syslog_panic("Cannot find auth token for server!\n");
248 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
249 us = xzmalloc(us_len);
251 err = username_msg(username, strlen(username) + 1,
252 us + crypto_box_zerobytes,
253 us_len - crypto_box_zerobytes);
254 if (unlikely(err))
255 syslog_panic("Cannot create init message!\n");
257 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
258 (unsigned char **) &cbuff);
259 if (unlikely(clen <= 0))
260 syslog_panic("Init encrypt error!\n");
262 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
263 if (unlikely(err))
264 syslog_panic("Cannot create init hmac message!\n");
266 pad = ((uint32_t) secrand()) % 200;
267 msg_len = clen + sizeof(auth) + pad;
269 msg = xzmalloc(msg_len);
270 memcpy(msg, auth, sizeof(auth));
271 memcpy(msg + sizeof(auth), cbuff, clen);
273 for (i = sizeof(auth) + clen; i < msg_len; ++i)
274 msg[i] = (uint8_t) secrand();
276 hdr.payload = htons((uint16_t) msg_len);
278 set_sock_cork(fd, udp);
280 write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
281 write_exact(fd, msg, msg_len, 0);
283 set_sock_uncork(fd, udp);
285 xfree(msg);
286 xfree(us);
289 static void notify_close(int fd)
291 struct ct_proto hdr;
293 memset(&hdr, 0, sizeof(hdr));
295 hdr.flags |= PROTO_FLAG_EXIT;
296 hdr.payload = 0;
298 write_exact(fd, &hdr, sizeof(hdr), 0);
301 int client_main(char *home, char *dev, char *host, char *port, int udp)
303 int fd = -1, tunfd = 0, retry_server = 0;
304 int ret, try = 1, i;
305 struct addrinfo hints, *ahead, *ai;
306 struct pollfd fds[2];
307 struct curve25519_proto *p;
308 struct curve25519_struct *c;
309 char *buff;
310 size_t blen = TUNBUFF_SIZ; //FIXME
312 retry:
313 if (!retry_server) {
314 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
315 syslog(LOG_INFO, "curvetun client booting!\n");
318 c = curve25519_tfm_alloc();
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_tfm_free(c);
333 fd = -1;
334 retry_server = 1;
335 closed_by_server = 0;
336 sleep(1);
337 goto retry;
340 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
341 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
342 if (fd < 0)
343 continue;
344 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
345 if (ret < 0) {
346 syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
347 try++, strerror(errno));
348 close(fd);
349 fd = -1;
350 continue;
353 set_socket_keepalive(fd);
354 set_mtu_disc_dont(fd);
355 if (!udp)
356 set_tcp_nodelay(fd);
359 freeaddrinfo(ahead);
361 if (fd < 0) {
362 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
363 curve25519_tfm_free(c);
364 fd = -1;
365 retry_server = 1;
366 closed_by_server = 0;
367 sleep(1);
368 goto retry;
371 if (!retry_server)
372 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
373 IFF_TUN | IFF_NO_PI);
375 set_nonblocking_sloppy(fd);
376 set_nonblocking_sloppy(tunfd);
378 memset(fds, 0, sizeof(fds));
379 fds[0].fd = fd;
380 fds[1].fd = tunfd;
381 fds[0].events = POLLIN;
382 fds[1].events = POLLIN;
384 buff = xmalloc_aligned(blen, 64);
386 notify_init(fd, udp, p, c, home);
388 syslog(LOG_INFO, "curvetun client ready!\n");
390 while (likely(!sigint && !closed_by_server)) {
391 poll(fds, 2, -1);
392 for (i = 0; i < 2; ++i) {
393 if ((fds[i].revents & POLLIN) != POLLIN)
394 continue;
395 if (fds[i].fd == tunfd) {
396 if (udp)
397 handler_udp_tun_to_net(tunfd, fd, p, c,
398 buff, blen);
399 else
400 handler_tcp_tun_to_net(tunfd, fd, p, c,
401 buff, blen);
402 } else if (fds[i].fd == fd) {
403 if (udp)
404 handler_udp_net_to_tun(fd, tunfd, p, c,
405 buff, blen);
406 else
407 handler_tcp_net_to_tun(fd, tunfd, p, c,
408 buff, blen);
413 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
415 if (!closed_by_server)
416 notify_close(fd);
418 xfree(buff);
419 close(fd);
420 curve25519_tfm_free(c);
422 /* tundev still active */
423 if (closed_by_server && !sigint) {
424 syslog(LOG_ERR, "curvetun connection retry attempt!\n");
425 fd = -1;
426 retry_server = 1;
427 closed_by_server = 0;
428 sleep(1);
429 goto retry;
432 close(tunfd);
433 syslog(LOG_INFO, "curvetun client shut down!\n");
434 closelog();
436 return 0;