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.
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>
26 #include <netinet/tcp.h>
27 #include <netinet/udp.h>
28 #include <linux/if_tun.h>
41 #include "crypto_auth_hmacsha512256.h"
43 extern sig_atomic_t sigint
;
44 static 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
,
52 ssize_t rlen
, err
, clen
;
54 size_t off
= sizeof(struct ct_proto
) + crypto_box_zerobytes
;
56 if (!buff
|| len
<= off
) {
63 while ((rlen
= read(sfd
, buff
+ off
, len
- off
)) > 0) {
64 hdr
= (struct ct_proto
*) buff
;
65 memset(hdr
, 0, sizeof(*hdr
));
68 clen
= curve25519_encode(c
, p
, (unsigned char *) (buff
+ off
-
69 crypto_box_zerobytes
), (rlen
+
70 crypto_box_zerobytes
), (unsigned char **)
72 if (unlikely(clen
<= 0)) {
73 syslog(LOG_ERR
, "UDP tunnel encrypt error!\n");
77 hdr
->payload
= htons((uint16_t) clen
);
80 setsockopt(dfd
, IPPROTO_UDP
, UDP_CORK
, &state
, sizeof(state
));
82 err
= write_exact(dfd
, hdr
, sizeof(struct ct_proto
), 0);
83 if (unlikely(err
< 0))
84 syslog(LOG_ERR
, "Error writing tunnel data to net: %s\n",
87 err
= write_exact(dfd
, cbuff
, clen
, 0);
88 if (unlikely(err
< 0))
89 syslog(LOG_ERR
, "Error writing tunnel data to net: %s\n",
93 setsockopt(dfd
, IPPROTO_UDP
, UDP_CORK
, &state
, sizeof(state
));
101 closed_by_server
= 1;
104 static void handler_udp_net_to_tun(int sfd
, int dfd
, struct curve25519_proto
*p
,
105 struct curve25519_struct
*c
, char *buff
,
109 ssize_t rlen
, err
, clen
;
110 struct ct_proto
*hdr
;
111 struct sockaddr_storage naddr
;
112 socklen_t nlen
= sizeof(naddr
);
119 memset(&naddr
, 0, sizeof(naddr
));
122 while ((rlen
= recvfrom(sfd
, buff
, len
, 0, (struct sockaddr
*) &naddr
,
124 hdr
= (struct ct_proto
*) buff
;
126 if (unlikely(rlen
< sizeof(struct ct_proto
)))
128 if (unlikely(rlen
- sizeof(*hdr
) != ntohs(hdr
->payload
)))
130 if (unlikely(ntohs(hdr
->payload
) == 0))
132 if (hdr
->flags
& PROTO_FLAG_EXIT
)
135 clen
= curve25519_decode(c
, p
, (unsigned char *) buff
+
136 sizeof(struct ct_proto
),
137 rlen
- sizeof(struct ct_proto
),
138 (unsigned char **) &cbuff
, NULL
);
139 if (unlikely(clen
<= 0)) {
140 syslog(LOG_ERR
, "UDP net decrypt error!\n");
143 cbuff
+= crypto_box_zerobytes
;
144 clen
-= crypto_box_zerobytes
;
145 err
= write(dfd
, cbuff
, clen
);
146 if (unlikely(err
< 0))
147 syslog(LOG_ERR
, "Error writing net data to tunnel: %s\n",
155 closed_by_server
= 1;
158 static void handler_tcp_tun_to_net(int sfd
, int dfd
, struct curve25519_proto
*p
,
159 struct curve25519_struct
*c
, char *buff
,
164 ssize_t rlen
, err
, clen
;
165 struct ct_proto
*hdr
;
166 size_t off
= sizeof(struct ct_proto
) + crypto_box_zerobytes
;
168 if (!buff
|| len
<= off
) {
174 memset(buff
, 0, len
);
175 while ((rlen
= read(sfd
, buff
+ off
, len
- off
)) > 0) {
176 hdr
= (struct ct_proto
*) buff
;
177 memset(hdr
, 0, sizeof(*hdr
));
180 clen
= curve25519_encode(c
, p
, (unsigned char *) (buff
+ off
-
181 crypto_box_zerobytes
), (rlen
+
182 crypto_box_zerobytes
), (unsigned char **)
184 if (unlikely(clen
<= 0)) {
185 syslog(LOG_ERR
, "TCP tunnel encrypt error!\n");
189 hdr
->payload
= htons((uint16_t) clen
);
192 setsockopt(dfd
, IPPROTO_TCP
, TCP_CORK
, &state
, sizeof(state
));
194 err
= write_exact(dfd
, hdr
, sizeof(struct ct_proto
), 0);
195 if (unlikely(err
< 0))
196 syslog(LOG_ERR
, "Error writing tunnel data to net: %s\n",
199 err
= write_exact(dfd
, cbuff
, clen
, 0);
200 if (unlikely(err
< 0))
201 syslog(LOG_ERR
, "Error writing tunnel data to net: %s\n",
205 setsockopt(dfd
, IPPROTO_TCP
, TCP_CORK
, &state
, sizeof(state
));
208 memset(buff
, 0, len
);
213 closed_by_server
= 1;
216 extern ssize_t
handler_tcp_read(int fd
, char *buff
, size_t len
);
218 static void handler_tcp_net_to_tun(int sfd
, int dfd
, struct curve25519_proto
*p
,
219 struct curve25519_struct
*c
, char *buff
,
223 ssize_t rlen
, err
, clen
;
224 struct ct_proto
*hdr
;
232 while ((rlen
= handler_tcp_read(sfd
, buff
, len
)) > 0) {
233 hdr
= (struct ct_proto
*) buff
;
235 if (unlikely(rlen
< sizeof(struct ct_proto
)))
237 if (unlikely(rlen
- sizeof(*hdr
) != ntohs(hdr
->payload
)))
239 if (unlikely(ntohs(hdr
->payload
) == 0))
241 if (hdr
->flags
& PROTO_FLAG_EXIT
)
244 clen
= curve25519_decode(c
, p
, (unsigned char *) buff
+
245 sizeof(struct ct_proto
),
246 rlen
- sizeof(struct ct_proto
),
247 (unsigned char **) &cbuff
, NULL
);
248 if (unlikely(clen
<= 0)) {
249 syslog(LOG_ERR
, "TCP net decrypt error!\n");
252 cbuff
+= crypto_box_zerobytes
;
253 clen
-= crypto_box_zerobytes
;
254 err
= write(dfd
, cbuff
, clen
);
255 if (unlikely(err
< 0))
256 syslog(LOG_ERR
, "Error writing net data to tunnel: %s\n",
264 closed_by_server
= 1;
267 static void notify_init(int fd
, int udp
, struct curve25519_proto
*p
,
268 struct curve25519_struct
*c
, char *home
)
272 size_t us_len
, msg_len
, pad
;
274 char username
[256], path
[PATH_MAX
], *us
, *cbuff
, *msg
;
275 unsigned char auth
[crypto_auth_hmacsha512256_BYTES
], *token
;
277 mt_init_by_random_device();
279 memset(&hdr
, 0, sizeof(hdr
));
280 hdr
.flags
|= PROTO_FLAG_INIT
;
282 memset(path
, 0, sizeof(path
));
283 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_USERNAM
);
284 memset(username
, 0, sizeof(username
));
286 fd2
= open_or_die(path
, O_RDONLY
);
287 err
= read(fd2
, username
, sizeof(username
));
288 username
[sizeof(username
) - 1] = 0;
291 token
= get_serv_store_entry_auth_token();
293 syslog_panic("Cannot find auth token for server!\n");
295 us_len
= sizeof(struct username_struct
) + crypto_box_zerobytes
;
296 us
= xzmalloc(us_len
);
297 err
= username_msg(username
, strlen(username
) + 1,
298 us
+ crypto_box_zerobytes
,
299 us_len
- crypto_box_zerobytes
);
301 syslog_panic("Cannot create init message!\n");
302 clen
= curve25519_encode(c
, p
, (unsigned char *) us
, us_len
,
303 (unsigned char **) &cbuff
);
304 if (unlikely(clen
<= 0))
305 syslog_panic("Init encrypt error!\n");
306 err
= crypto_auth_hmacsha512256(auth
, (unsigned char *) cbuff
, clen
, token
);
308 syslog_panic("Cannot create init hmac message!\n");
310 assert(132 == clen
+ sizeof(auth
));
312 pad
= mt_rand_int32() % 200;
313 msg_len
= clen
+ sizeof(auth
) + pad
;
314 msg
= xzmalloc(msg_len
);
315 memcpy(msg
, auth
, sizeof(auth
));
316 memcpy(msg
+ sizeof(auth
), cbuff
, clen
);
317 for (i
= sizeof(auth
) + clen
; i
< msg_len
; ++i
)
318 msg
[i
] = (uint8_t) mt_rand_int32();
319 hdr
.payload
= htons((uint16_t) msg_len
);
322 setsockopt(fd
, udp
? IPPROTO_UDP
: IPPROTO_TCP
,
323 udp
? UDP_CORK
: TCP_CORK
, &state
, sizeof(state
));
325 err
= write_exact(fd
, &hdr
, sizeof(struct ct_proto
), 0);
326 if (unlikely(err
< 0))
327 syslog(LOG_ERR
, "Error writing init data to net: %s\n",
330 err
= write_exact(fd
, msg
, msg_len
, 0);
331 if (unlikely(err
< 0))
332 syslog(LOG_ERR
, "Error writing init data to net: %s\n",
336 setsockopt(fd
, udp
? IPPROTO_UDP
: IPPROTO_TCP
,
337 udp
? UDP_CORK
: TCP_CORK
, &state
, sizeof(state
));
342 static void notify_close(int fd
)
347 memset(&hdr
, 0, sizeof(hdr
));
348 hdr
.flags
|= PROTO_FLAG_EXIT
;
351 err
= write_exact(fd
, &hdr
, sizeof(hdr
), 0);
352 if (unlikely(err
< 0))
353 syslog(LOG_ERR
, "Error writing close: %s\n",
357 int client_main(char *home
, char *dev
, char *host
, char *port
, int udp
)
359 int fd
= -1, tunfd
= 0, retry_server
= 0;
360 int ret
, try = 1, i
, one
, mtu
;
361 struct addrinfo hints
, *ahead
, *ai
;
362 struct sockaddr_in6
*saddr6
;
363 struct pollfd fds
[2];
364 struct curve25519_proto
*p
;
365 struct curve25519_struct
*c
;
367 size_t blen
= TUNBUFF_SIZ
; //FIXME
371 openlog("curvetun", LOG_PID
| LOG_CONS
| LOG_NDELAY
, LOG_DAEMON
);
372 syslog(LOG_INFO
, "curvetun client booting!\n");
375 c
= xmalloc(sizeof(struct curve25519_struct
));
376 ret
= curve25519_alloc_or_maybe_die(c
);
378 syslog_panic("Cannot init curve!\n");
380 p
= get_serv_store_entry_proto_inf();
382 syslog_panic("Cannot proto!\n");
384 memset(&hints
, 0, sizeof(hints
));
385 hints
.ai_family
= PF_UNSPEC
;
386 hints
.ai_socktype
= udp
? SOCK_DGRAM
: SOCK_STREAM
;
387 hints
.ai_protocol
= udp
? IPPROTO_UDP
: IPPROTO_TCP
;
388 hints
.ai_flags
= AI_NUMERICSERV
;
390 ret
= getaddrinfo(host
, port
, &hints
, &ahead
);
392 syslog(LOG_ERR
, "Cannot get address info! Retry!\n");
397 closed_by_server
= 0;
402 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
403 if (ai
->ai_family
== PF_INET6
)
404 saddr6
= (struct sockaddr_in6
*) ai
->ai_addr
;
405 fd
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
408 ret
= connect(fd
, ai
->ai_addr
, ai
->ai_addrlen
);
410 syslog(LOG_ERR
, "Cannot connect to remote, try %d: %s!\n",
411 try++, strerror(errno
));
417 setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &one
, sizeof(one
));
418 mtu
= IP_PMTUDISC_DONT
;
419 setsockopt(fd
, SOL_IP
, IP_MTU_DISCOVER
, &mtu
, sizeof(mtu
));
422 setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &one
,
429 syslog(LOG_ERR
, "Cannot create socket! Retry!\n");
434 closed_by_server
= 0;
440 tunfd
= tun_open_or_die(dev
? dev
: DEVNAME_CLIENT
,
441 IFF_TUN
| IFF_NO_PI
);
443 set_nonblocking_sloppy(fd
);
444 set_nonblocking_sloppy(tunfd
);
446 memset(fds
, 0, sizeof(fds
));
449 fds
[0].events
= POLLIN
;
450 fds
[1].events
= POLLIN
;
452 buff
= xmalloc_aligned(blen
, 64);
453 notify_init(fd
, udp
, p
, c
, home
);
454 syslog(LOG_INFO
, "curvetun client ready!\n");
456 while (likely(!sigint
&& !closed_by_server
)) {
458 for (i
= 0; i
< 2; ++i
) {
459 if ((fds
[i
].revents
& POLLIN
) != POLLIN
)
461 if (fds
[i
].fd
== tunfd
) {
463 handler_udp_tun_to_net(tunfd
, fd
, p
, c
,
466 handler_tcp_tun_to_net(tunfd
, fd
, p
, c
,
468 } else if (fds
[i
].fd
== fd
) {
470 handler_udp_net_to_tun(fd
, tunfd
, p
, c
,
473 handler_tcp_net_to_tun(fd
, tunfd
, p
, c
,
479 syslog(LOG_INFO
, "curvetun client prepare shut down!\n");
480 if (!closed_by_server
)
487 /* tundev still active */
488 if (closed_by_server
&& !sigint
) {
489 syslog(LOG_ERR
, "curvetun connection retry attempt!\n");
492 closed_by_server
= 0;
498 syslog(LOG_INFO
, "curvetun client shut down!\n");