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.
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>
24 #include <netinet/tcp.h>
25 #include <netinet/udp.h>
26 #include <linux/if_tun.h>
35 #include "ct_servmgmt.h"
36 #include "ct_usermgmt.h"
37 #include "crypto_auth_hmacsha512256.h"
39 extern volatile sig_atomic_t sigint
;
40 static volatile sig_atomic_t closed_by_server
= 0;
42 static void handler_udp_tun_to_net(int sfd
, int dfd
, struct curve25519_proto
*p
,
43 struct curve25519_struct
*c
, char *buff
,
49 size_t off
= sizeof(struct ct_proto
) + crypto_box_zerobytes
;
51 if (!buff
|| len
<= off
)
55 while ((rlen
= read(sfd
, buff
+ off
, len
- off
)) > 0) {
56 hdr
= (struct ct_proto
*) buff
;
58 memset(hdr
, 0, sizeof(*hdr
));
61 clen
= curve25519_encode(c
, p
, (unsigned char *) (buff
+ off
-
62 crypto_box_zerobytes
), (rlen
+
63 crypto_box_zerobytes
), (unsigned char **)
65 if (unlikely(clen
<= 0))
68 hdr
->payload
= htons((uint16_t) clen
);
72 write_exact(dfd
, hdr
, sizeof(struct ct_proto
), 0);
73 write_exact(dfd
, cbuff
, clen
, 0);
85 static void handler_udp_net_to_tun(int sfd
, int dfd
, struct curve25519_proto
*p
,
86 struct curve25519_struct
*c
, char *buff
,
92 struct sockaddr_storage naddr
;
94 socklen_t nlen
= sizeof(naddr
);
99 memset(&naddr
, 0, sizeof(naddr
));
100 while ((rlen
= recvfrom(sfd
, buff
, len
, 0, (struct sockaddr
*) &naddr
,
102 hdr
= (struct ct_proto
*) buff
;
104 if (unlikely(rlen
< sizeof(struct ct_proto
)))
106 if (unlikely(rlen
- sizeof(*hdr
) != ntohs(hdr
->payload
)))
108 if (unlikely(ntohs(hdr
->payload
) == 0))
110 if (hdr
->flags
& PROTO_FLAG_EXIT
)
113 clen
= curve25519_decode(c
, p
, (unsigned char *) buff
+
114 sizeof(struct ct_proto
),
115 rlen
- sizeof(struct ct_proto
),
116 (unsigned char **) &cbuff
, NULL
);
117 if (unlikely(clen
<= 0))
120 cbuff
+= crypto_box_zerobytes
;
121 clen
-= crypto_box_zerobytes
;
123 if (write(dfd
, cbuff
, clen
)) { ; }
128 closed_by_server
= 1;
131 static void handler_tcp_tun_to_net(int sfd
, int dfd
, struct curve25519_proto
*p
,
132 struct curve25519_struct
*c
, char *buff
,
137 struct ct_proto
*hdr
;
138 size_t off
= sizeof(struct ct_proto
) + crypto_box_zerobytes
;
140 if (!buff
|| len
<= off
)
143 memset(buff
, 0, len
);
144 while ((rlen
= read(sfd
, buff
+ off
, len
- off
)) > 0) {
145 hdr
= (struct ct_proto
*) buff
;
147 memset(hdr
, 0, sizeof(*hdr
));
150 clen
= curve25519_encode(c
, p
, (unsigned char *) (buff
+ off
-
151 crypto_box_zerobytes
), (rlen
+
152 crypto_box_zerobytes
), (unsigned char **)
154 if (unlikely(clen
<= 0))
157 hdr
->payload
= htons((uint16_t) clen
);
161 write_exact(dfd
, hdr
, sizeof(struct ct_proto
), 0);
162 write_exact(dfd
, cbuff
, clen
, 0);
166 memset(buff
, 0, len
);
171 closed_by_server
= 1;
174 extern ssize_t
handler_tcp_read(int fd
, char *buff
, size_t len
);
176 static void handler_tcp_net_to_tun(int sfd
, int dfd
, struct curve25519_proto
*p
,
177 struct curve25519_struct
*c
, char *buff
,
182 struct ct_proto
*hdr
;
187 while ((rlen
= handler_tcp_read(sfd
, buff
, len
)) > 0) {
188 hdr
= (struct ct_proto
*) buff
;
190 if (unlikely(rlen
< sizeof(struct ct_proto
)))
192 if (unlikely(rlen
- sizeof(*hdr
) != ntohs(hdr
->payload
)))
194 if (unlikely(ntohs(hdr
->payload
) == 0))
196 if (hdr
->flags
& PROTO_FLAG_EXIT
)
199 clen
= curve25519_decode(c
, p
, (unsigned char *) buff
+
200 sizeof(struct ct_proto
),
201 rlen
- sizeof(struct ct_proto
),
202 (unsigned char **) &cbuff
, NULL
);
203 if (unlikely(clen
<= 0))
206 cbuff
+= crypto_box_zerobytes
;
207 clen
-= crypto_box_zerobytes
;
209 if (write(dfd
, cbuff
, clen
)) { ; }
214 closed_by_server
= 1;
217 static void notify_init(int fd
, int udp
, struct curve25519_proto
*p
,
218 struct curve25519_struct
*c
, char *home
)
222 size_t us_len
, msg_len
, pad
;
224 char username
[256], path
[PATH_MAX
], *us
, *cbuff
, *msg
;
225 unsigned char auth
[crypto_auth_hmacsha512256_BYTES
], *token
;
227 memset(&hdr
, 0, sizeof(hdr
));
228 hdr
.flags
|= PROTO_FLAG_INIT
;
230 memset(path
, 0, sizeof(path
));
231 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_USERNAM
);
233 fd2
= open_or_die(path
, O_RDONLY
);
235 memset(username
, 0, sizeof(username
));
236 err
= read(fd2
, username
, sizeof(username
));
237 username
[sizeof(username
) - 1] = 0;
241 token
= get_serv_store_entry_auth_token();
243 syslog_panic("Cannot find auth token for server!\n");
245 us_len
= sizeof(struct username_struct
) + crypto_box_zerobytes
;
246 us
= xzmalloc(us_len
);
248 err
= username_msg(username
, strlen(username
) + 1,
249 us
+ crypto_box_zerobytes
,
250 us_len
- crypto_box_zerobytes
);
252 syslog_panic("Cannot create init message!\n");
254 clen
= curve25519_encode(c
, p
, (unsigned char *) us
, us_len
,
255 (unsigned char **) &cbuff
);
256 if (unlikely(clen
<= 0))
257 syslog_panic("Init encrypt error!\n");
259 err
= crypto_auth_hmacsha512256(auth
, (unsigned char *) cbuff
, clen
, token
);
261 syslog_panic("Cannot create init hmac message!\n");
263 pad
= ((uint32_t) secrand()) % 200;
264 msg_len
= clen
+ sizeof(auth
) + pad
;
266 msg
= xzmalloc(msg_len
);
267 memcpy(msg
, auth
, sizeof(auth
));
268 memcpy(msg
+ sizeof(auth
), cbuff
, clen
);
270 for (i
= sizeof(auth
) + clen
; i
< msg_len
; ++i
)
271 msg
[i
] = (uint8_t) secrand();
273 hdr
.payload
= htons((uint16_t) msg_len
);
275 set_sock_cork(fd
, udp
);
277 write_exact(fd
, &hdr
, sizeof(struct ct_proto
), 0);
278 write_exact(fd
, msg
, msg_len
, 0);
280 set_sock_uncork(fd
, udp
);
286 static void notify_close(int fd
)
290 memset(&hdr
, 0, sizeof(hdr
));
292 hdr
.flags
|= PROTO_FLAG_EXIT
;
295 write_exact(fd
, &hdr
, sizeof(hdr
), 0);
298 int client_main(char *home
, char *dev
, char *host
, char *port
, int udp
)
300 int fd
= -1, tunfd
= 0, retry_server
= 0;
302 struct addrinfo hints
, *ahead
, *ai
;
303 struct pollfd fds
[2];
304 struct curve25519_proto
*p
;
305 struct curve25519_struct
*c
;
307 size_t blen
= TUNBUFF_SIZ
; //FIXME
311 openlog("curvetun", LOG_PID
| LOG_CONS
| LOG_NDELAY
, LOG_DAEMON
);
312 syslog(LOG_INFO
, "curvetun client booting!\n");
315 c
= xmalloc(sizeof(struct curve25519_struct
));
317 curve25519_alloc_or_maybe_die(c
);
319 p
= get_serv_store_entry_proto_inf();
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
);
331 syslog(LOG_ERR
, "Cannot get address info! Retry!\n");
336 closed_by_server
= 0;
341 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
342 fd
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
345 ret
= connect(fd
, ai
->ai_addr
, ai
->ai_addrlen
);
347 syslog(LOG_ERR
, "Cannot connect to remote, try %d: %s!\n",
348 try++, strerror(errno
));
354 set_socket_keepalive(fd
);
355 set_mtu_disc_dont(fd
);
363 syslog(LOG_ERR
, "Cannot create socket! Retry!\n");
368 closed_by_server
= 0;
374 tunfd
= tun_open_or_die(dev
? dev
: DEVNAME_CLIENT
,
375 IFF_TUN
| IFF_NO_PI
);
377 set_nonblocking_sloppy(fd
);
378 set_nonblocking_sloppy(tunfd
);
380 memset(fds
, 0, sizeof(fds
));
383 fds
[0].events
= POLLIN
;
384 fds
[1].events
= POLLIN
;
386 buff
= xmalloc_aligned(blen
, 64);
388 notify_init(fd
, udp
, p
, c
, home
);
390 syslog(LOG_INFO
, "curvetun client ready!\n");
392 while (likely(!sigint
&& !closed_by_server
)) {
394 for (i
= 0; i
< 2; ++i
) {
395 if ((fds
[i
].revents
& POLLIN
) != POLLIN
)
397 if (fds
[i
].fd
== tunfd
) {
399 handler_udp_tun_to_net(tunfd
, fd
, p
, c
,
402 handler_tcp_tun_to_net(tunfd
, fd
, p
, c
,
404 } else if (fds
[i
].fd
== fd
) {
406 handler_udp_net_to_tun(fd
, tunfd
, p
, c
,
409 handler_tcp_net_to_tun(fd
, tunfd
, p
, c
,
415 syslog(LOG_INFO
, "curvetun client prepare shut down!\n");
417 if (!closed_by_server
)
425 /* tundev still active */
426 if (closed_by_server
&& !sigint
) {
427 syslog(LOG_ERR
, "curvetun connection retry attempt!\n");
430 closed_by_server
= 0;
436 syslog(LOG_INFO
, "curvetun client shut down!\n");