html: some further minor tweaks on the index page
[netsniff-ng.git] / src / ct_client.c
blob1fff476b6365ed3dc5e976881a9f47146484166c
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 <assert.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <sys/poll.h>
26 #include <netinet/tcp.h>
27 #include <netinet/udp.h>
28 #include <linux/if_tun.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 "servmgmt.h"
39 #include "usermgmt.h"
40 #include "compiler.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 int state;
51 char *cbuff;
52 ssize_t rlen, err, clen;
53 struct ct_proto *hdr;
54 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
55 if (!buff || len <= off) {
56 errno = EINVAL;
57 return;
59 errno = 0;
60 memset(buff, 0, len);
61 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
62 hdr = (struct ct_proto *) buff;
63 memset(hdr, 0, sizeof(*hdr));
64 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 syslog(LOG_ERR, "UDP tunnel encrypt error!\n");
71 goto close;
73 hdr->payload = htons((uint16_t) clen);
74 state = 1;
75 setsockopt(dfd, IPPROTO_UDP, UDP_CORK, &state, sizeof(state));
76 err = write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
77 if (unlikely(err < 0))
78 syslog(LOG_ERR, "Error writing tunnel data to net: %s\n",
79 strerror(errno));
80 err = write_exact(dfd, cbuff, clen, 0);
81 if (unlikely(err < 0))
82 syslog(LOG_ERR, "Error writing tunnel data to net: %s\n",
83 strerror(errno));
84 state = 0;
85 setsockopt(dfd, IPPROTO_UDP, UDP_CORK, &state, sizeof(state));
86 errno = 0;
87 memset(buff, 0, len);
89 return;
90 close:
91 closed_by_server = 1;
94 static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
95 struct curve25519_struct *c, char *buff,
96 size_t len)
98 char *cbuff;
99 ssize_t rlen, err, clen;
100 struct ct_proto *hdr;
101 struct sockaddr_storage naddr;
102 socklen_t nlen = sizeof(naddr);
103 if (!buff || !len) {
104 errno = EINVAL;
105 return;
107 memset(&naddr, 0, sizeof(naddr));
108 errno = 0;
109 while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr,
110 &nlen)) > 0) {
111 hdr = (struct ct_proto *) buff;
112 if (unlikely(rlen < sizeof(struct ct_proto)))
113 goto close;
114 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
115 goto close;
116 if (unlikely(ntohs(hdr->payload) == 0))
117 goto close;
118 if (hdr->flags & PROTO_FLAG_EXIT)
119 goto close;
120 clen = curve25519_decode(c, p, (unsigned char *) buff +
121 sizeof(struct ct_proto),
122 rlen - sizeof(struct ct_proto),
123 (unsigned char **) &cbuff, NULL);
124 if (unlikely(clen <= 0)) {
125 syslog(LOG_ERR, "UDP net decrypt error!\n");
126 goto close;
128 cbuff += crypto_box_zerobytes;
129 clen -= crypto_box_zerobytes;
130 err = write(dfd, cbuff, clen);
131 if (unlikely(err < 0))
132 syslog(LOG_ERR, "Error writing net data to tunnel: %s\n",
133 strerror(errno));
134 errno = 0;
136 return;
137 close:
138 closed_by_server = 1;
141 static void handler_tcp_tun_to_net(int sfd, int dfd, struct curve25519_proto *p,
142 struct curve25519_struct *c, char *buff,
143 size_t len)
145 int state;
146 char *cbuff;
147 ssize_t rlen, err, clen;
148 struct ct_proto *hdr;
149 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
150 if (!buff || len <= off) {
151 errno = EINVAL;
152 return;
154 errno = 0;
155 memset(buff, 0, len);
156 while ((rlen = read(sfd, buff + off, len - off)) > 0) {
157 hdr = (struct ct_proto *) buff;
158 memset(hdr, 0, sizeof(*hdr));
159 hdr->flags = 0;
160 clen = curve25519_encode(c, p, (unsigned char *) (buff + off -
161 crypto_box_zerobytes), (rlen +
162 crypto_box_zerobytes), (unsigned char **)
163 &cbuff);
164 if (unlikely(clen <= 0)) {
165 syslog(LOG_ERR, "TCP tunnel encrypt error!\n");
166 goto close;
168 hdr->payload = htons((uint16_t) clen);
169 state = 1;
170 setsockopt(dfd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
171 err = write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
172 if (unlikely(err < 0))
173 syslog(LOG_ERR, "Error writing tunnel data to net: %s\n",
174 strerror(errno));
175 err = write_exact(dfd, cbuff, clen, 0);
176 if (unlikely(err < 0))
177 syslog(LOG_ERR, "Error writing tunnel data to net: %s\n",
178 strerror(errno));
179 state = 0;
180 setsockopt(dfd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
181 errno = 0;
182 memset(buff, 0, len);
184 return;
185 close:
186 closed_by_server = 1;
189 extern ssize_t handler_tcp_read(int fd, char *buff, size_t len);
191 static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p,
192 struct curve25519_struct *c, char *buff,
193 size_t len)
195 char *cbuff;
196 ssize_t rlen, err, clen;
197 struct ct_proto *hdr;
198 if (!buff || !len) {
199 errno = EINVAL;
200 return;
202 errno = 0;
203 while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) {
204 hdr = (struct ct_proto *) buff;
205 if (unlikely(rlen < sizeof(struct ct_proto)))
206 goto close;
207 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
208 goto close;
209 if (unlikely(ntohs(hdr->payload) == 0))
210 goto close;
211 if (hdr->flags & PROTO_FLAG_EXIT)
212 goto close;
213 clen = curve25519_decode(c, p, (unsigned char *) buff +
214 sizeof(struct ct_proto),
215 rlen - sizeof(struct ct_proto),
216 (unsigned char **) &cbuff, NULL);
217 if (unlikely(clen <= 0)) {
218 syslog(LOG_ERR, "TCP net decrypt error!\n");
219 goto close;
221 cbuff += crypto_box_zerobytes;
222 clen -= crypto_box_zerobytes;
223 err = write(dfd, cbuff, clen);
224 if (unlikely(err < 0))
225 syslog(LOG_ERR, "Error writing net data to tunnel: %s\n",
226 strerror(errno));
227 errno = 0;
229 return;
230 close:
231 closed_by_server = 1;
234 static void notify_init(int fd, int udp, struct curve25519_proto *p,
235 struct curve25519_struct *c, char *home)
237 int state, fd2, i;
238 ssize_t err, clen;
239 size_t us_len, msg_len, pad;
240 struct ct_proto hdr;
241 char username[256], path[PATH_MAX], *us, *cbuff, *msg;
242 unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;
243 mt_init_by_random_device();
244 memset(&hdr, 0, sizeof(hdr));
245 hdr.flags |= PROTO_FLAG_INIT;
246 memset(path, 0, sizeof(path));
247 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
248 memset(username, 0, sizeof(username));
249 fd2 = open_or_die(path, O_RDONLY);
250 err = read(fd2, username, sizeof(username));
251 username[sizeof(username) - 1] = 0;
252 close(fd2);
253 token = get_serv_store_entry_auth_token();
254 if (!token)
255 syslog_panic("Cannot find auth token for server!\n");
256 us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
257 us = xzmalloc(us_len);
258 err = username_msg(username, strlen(username) + 1,
259 us + crypto_box_zerobytes,
260 us_len - crypto_box_zerobytes);
261 if (unlikely(err))
262 syslog_panic("Cannot create init message!\n");
263 clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
264 (unsigned char **) &cbuff);
265 if (unlikely(clen <= 0))
266 syslog_panic("Init encrypt error!\n");
267 err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
268 if (unlikely(err))
269 syslog_panic("Cannot create init hmac message!\n");
270 assert(132 == clen + sizeof(auth));
271 pad = mt_rand_int32() % 200;
272 msg_len = clen + sizeof(auth) + pad;
273 msg = xzmalloc(msg_len);
274 memcpy(msg, auth, sizeof(auth));
275 memcpy(msg + sizeof(auth), cbuff, clen);
276 for (i = sizeof(auth) + clen; i < msg_len; ++i)
277 msg[i] = (uint8_t) mt_rand_int32();
278 hdr.payload = htons((uint16_t) msg_len);
279 state = 1;
280 setsockopt(fd, udp ? IPPROTO_UDP : IPPROTO_TCP,
281 udp ? UDP_CORK : TCP_CORK, &state, sizeof(state));
282 err = write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
283 if (unlikely(err < 0))
284 syslog(LOG_ERR, "Error writing init data to net: %s\n",
285 strerror(errno));
286 err = write_exact(fd, msg, msg_len, 0);
287 if (unlikely(err < 0))
288 syslog(LOG_ERR, "Error writing init data to net: %s\n",
289 strerror(errno));
290 state = 0;
291 setsockopt(fd, udp ? IPPROTO_UDP : IPPROTO_TCP,
292 udp ? UDP_CORK : TCP_CORK, &state, sizeof(state));
293 xfree(msg);
294 xfree(us);
297 static void notify_close(int fd)
299 ssize_t err;
300 struct ct_proto hdr;
301 memset(&hdr, 0, sizeof(hdr));
302 hdr.flags |= PROTO_FLAG_EXIT;
303 hdr.payload = 0;
304 err = write_exact(fd, &hdr, sizeof(hdr), 0);
305 if (unlikely(err < 0))
306 syslog(LOG_ERR, "Error writing close: %s\n",
307 strerror(errno));
310 int client_main(char *home, char *dev, char *host, char *port, int udp)
312 int fd = -1, tunfd = 0, retry_server = 0;
313 int ret, try = 1, i, one, mtu;
314 struct addrinfo hints, *ahead, *ai;
315 struct sockaddr_in6 *saddr6;
316 struct pollfd fds[2];
317 struct curve25519_proto *p;
318 struct curve25519_struct *c;
319 char *buff;
320 size_t blen = TUNBUFF_SIZ; //FIXME
321 retry:
322 if (!retry_server) {
323 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
324 syslog(LOG_INFO, "curvetun client booting!\n");
326 c = xmalloc(sizeof(struct curve25519_struct));
327 ret = curve25519_alloc_or_maybe_die(c);
328 if (ret < 0)
329 syslog_panic("Cannot init curve!\n");
330 p = get_serv_store_entry_proto_inf();
331 if (!p)
332 syslog_panic("Cannot proto!\n");
333 memset(&hints, 0, sizeof(hints));
334 hints.ai_family = PF_UNSPEC;
335 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
336 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
337 hints.ai_flags = AI_NUMERICSERV;
338 ret = getaddrinfo(host, port, &hints, &ahead);
339 if (ret < 0) {
340 syslog(LOG_ERR, "Cannot get address info! Retry!\n");
341 curve25519_free(c);
342 xfree(c);
343 fd = -1;
344 retry_server = 1;
345 closed_by_server = 0;
346 sleep(1);
347 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;
363 one = 1;
364 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
365 mtu = IP_PMTUDISC_DONT;
366 setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu));
367 if (!udp) {
368 one = 1;
369 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
370 sizeof(one));
373 freeaddrinfo(ahead);
374 if (fd < 0) {
375 syslog(LOG_ERR, "Cannot create socket! Retry!\n");
376 curve25519_free(c);
377 xfree(c);
378 fd = -1;
379 retry_server = 1;
380 closed_by_server = 0;
381 sleep(1);
382 goto retry;
384 if (!retry_server)
385 tunfd = tun_open_or_die(dev ? dev : DEVNAME_CLIENT,
386 IFF_TUN | IFF_NO_PI);
387 set_nonblocking_sloppy(fd);
388 set_nonblocking_sloppy(tunfd);
389 memset(fds, 0, sizeof(fds));
390 fds[0].fd = fd;
391 fds[1].fd = tunfd;
392 fds[0].events = POLLIN;
393 fds[1].events = POLLIN;
394 buff = xmalloc_aligned(blen, 64);
395 notify_init(fd, udp, p, c, home);
396 syslog(LOG_INFO, "curvetun client ready!\n");
397 while (likely(!sigint && !closed_by_server)) {
398 poll(fds, 2, -1);
399 for (i = 0; i < 2; ++i) {
400 if ((fds[i].revents & POLLIN) != POLLIN)
401 continue;
402 if (fds[i].fd == tunfd) {
403 if (udp)
404 handler_udp_tun_to_net(tunfd, fd, p, c,
405 buff, blen);
406 else
407 handler_tcp_tun_to_net(tunfd, fd, p, c,
408 buff, blen);
409 } else if (fds[i].fd == fd) {
410 if (udp)
411 handler_udp_net_to_tun(fd, tunfd, p, c,
412 buff, blen);
413 else
414 handler_tcp_net_to_tun(fd, tunfd, p, c,
415 buff, blen);
419 syslog(LOG_INFO, "curvetun client prepare shut down!\n");
420 if (!closed_by_server)
421 notify_close(fd);
422 xfree(buff);
423 close(fd);
424 curve25519_free(c);
425 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;
435 close(tunfd);
436 syslog(LOG_INFO, "curvetun client shut down!\n");
437 closelog();
438 return 0;