87f9b51b45d28945b7b77c25fc6de0e97f47a323
[tinc] / src / sptps_test.c
1 /*
2     sptps_test.c -- Simple Peer-to-Peer Security test program
3     Copyright (C) 2011-2014 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #ifdef HAVE_LINUX
23 #include <linux/if_tun.h>
24 #endif
25
26 #include <getopt.h>
27
28 #ifdef HAVE_MINGW
29 #include <pthread.h>
30 #endif
31
32 #include "crypto.h"
33 #include "ecdsa.h"
34 #include "sptps.h"
35 #include "utils.h"
36
37 #ifndef MAX
38 #define MAX(a, b) ((a) > (b) ? (a) : (b))
39 #endif
40
41 #ifndef HAVE_MINGW
42 #define closesocket(s) close(s)
43 #endif
44
45 // Symbols necessary to link with logger.o
46 bool send_request(void *c, const char *msg, ...) {
47         (void)c;
48         (void)msg;
49         return false;
50 }
51
52 struct list_t *connection_list = NULL;
53
54 bool send_meta(void *c, const char *msg, int len) {
55         (void)c;
56         (void)msg;
57         (void)len;
58         return false;
59 }
60
61 char *logfilename = NULL;
62 bool do_detach = false;
63 struct timeval now;
64
65 static bool special;
66 static bool verbose;
67 static bool readonly;
68 static bool writeonly;
69 static int in = 0;
70 static int out = 1;
71 static int addressfamily = AF_UNSPEC;
72
73 static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
74         (void)type;
75         char hex[len * 2 + 1];
76         bin2hex(data, hex, len);
77
78         if(verbose) {
79                 fprintf(stderr, "Sending %d bytes of data:\n%s\n", (int)len, hex);
80         }
81
82         const int *sock = handle;
83
84         if((size_t)send(*sock, data, len, 0) != len) {
85                 return false;
86         }
87
88         return true;
89 }
90
91 static bool receive_record(void *handle, uint8_t type, const void *data, uint16_t len) {
92         (void)handle;
93
94         if(verbose) {
95                 fprintf(stderr, "Received type %d record of %u bytes:\n", type, len);
96         }
97
98         if(!writeonly) {
99                 write(out, data, len);
100         }
101
102         return true;
103 }
104
105 static struct option const long_options[] = {
106         {"datagram", no_argument, NULL, 'd'},
107         {"quit", no_argument, NULL, 'q'},
108         {"readonly", no_argument, NULL, 'r'},
109         {"writeonly", no_argument, NULL, 'w'},
110         {"packet-loss", required_argument, NULL, 'L'},
111         {"replay-window", required_argument, NULL, 'W'},
112         {"special", no_argument, NULL, 's'},
113         {"verbose", required_argument, NULL, 'v'},
114         {"help", no_argument, NULL, 1},
115         {NULL, 0, NULL, 0}
116 };
117
118 const char *program_name;
119
120 static void usage() {
121         fprintf(stderr, "Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n\n", program_name);
122         fprintf(stderr, "Valid options are:\n"
123                 "  -d, --datagram          Enable datagram mode.\n"
124                 "  -q, --quit              Quit when EOF occurs on stdin.\n"
125                 "  -r, --readonly          Only send data from the socket to stdout.\n"
126 #ifdef HAVE_LINUX
127                 "  -t, --tun               Use a tun device instead of stdio.\n"
128 #endif
129                 "  -w, --writeonly         Only send data from stdin to the socket.\n"
130                 "  -L, --packet-loss RATE  Fake packet loss of RATE percent.\n"
131                 "  -R, --replay-window N   Set replay window to N bytes.\n"
132                 "  -s, --special           Enable special handling of lines starting with #, ^ and $.\n"
133                 "  -v, --verbose           Display debug messages.\n"
134                 "  -4                      Use IPv4.\n"
135                 "  -6                      Use IPv6.\n"
136                 "\n");
137         fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
138 }
139
140 #ifdef HAVE_MINGW
141
142 int stdin_sock_fd = -1;
143
144 // Windows does not allow calling select() on anything but sockets. Therefore,
145 // to keep the same code as on other operating systems, we have to put a
146 // separate thread between the stdin and the sptps loop way below. This thread
147 // reads stdin and sends its content to the main thread through a TCP socket,
148 // which can be properly select()'ed.
149 void *stdin_reader_thread(void *arg) {
150         struct sockaddr_in sa;
151         socklen_t sa_size = sizeof(sa);
152
153         while(true) {
154                 int peer_fd = accept(stdin_sock_fd, (struct sockaddr *) &sa, &sa_size);
155
156                 if(peer_fd < 0) {
157                         fprintf(stderr, "accept() failed: %s\n", strerror(errno));
158                         continue;
159                 }
160
161                 if(verbose) {
162                         fprintf(stderr, "New connection received from :%d\n", ntohs(sa.sin_port));
163                 }
164
165                 char buf[1024];
166                 ssize_t nread;
167
168                 while((nread = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
169                         if(verbose) {
170                                 fprintf(stderr, "Read %lld bytes from input\n", nread);
171                         }
172
173                         char *start = buf;
174                         ssize_t nleft = nread;
175
176                         while(nleft) {
177                                 ssize_t nsend = send(peer_fd, start, nleft, 0);
178
179                                 if(nsend < 0) {
180                                         if(sockwouldblock(sockerrno)) {
181                                                 continue;
182                                         }
183
184                                         break;
185                                 }
186
187                                 start += nsend;
188                                 nleft -= nsend;
189                         }
190
191                         if(nleft) {
192                                 fprintf(stderr, "Could not send data: %s\n", strerror(errno));
193                                 break;
194                         }
195
196                         if(verbose) {
197                                 fprintf(stderr, "Sent %lld bytes to peer\n", nread);
198                         }
199                 }
200
201                 closesocket(peer_fd);
202         }
203
204         closesocket(stdin_sock_fd);
205         stdin_sock_fd = -1;
206 }
207
208 int start_input_reader() {
209         if(stdin_sock_fd != -1) {
210                 fprintf(stderr, "stdin thread can only be started once.\n");
211                 return -1;
212         }
213
214         stdin_sock_fd = socket(AF_INET, SOCK_STREAM, 0);
215
216         if(stdin_sock_fd < 0) {
217                 fprintf(stderr, "Could not create server socket: %s\n", strerror(errno));
218                 return -1;
219         }
220
221         struct sockaddr_in serv_sa;
222
223         memset(&serv_sa, 0, sizeof(serv_sa));
224
225         serv_sa.sin_family = AF_INET;
226
227         serv_sa.sin_addr.s_addr = htonl(0x7f000001); // 127.0.0.1
228
229         int res = bind(stdin_sock_fd, (struct sockaddr *)&serv_sa, sizeof(serv_sa));
230
231         if(res < 0) {
232                 fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
233                 goto server_err;
234         }
235
236         if(listen(stdin_sock_fd, 1) < 0) {
237                 fprintf(stderr, "Could not listen: %s\n", strerror(errno));
238                 goto server_err;
239         }
240
241         struct sockaddr_in connect_sa;
242
243         socklen_t addr_len = sizeof(connect_sa);
244
245         if(getsockname(stdin_sock_fd, (struct sockaddr *)&connect_sa, &addr_len) < 0) {
246                 fprintf(stderr, "Could not determine the address of the stdin thread socket\n");
247                 goto server_err;
248         }
249
250         if(verbose) {
251                 fprintf(stderr, "stdin thread is listening on :%d\n", ntohs(connect_sa.sin_port));
252         }
253
254         pthread_t th;
255         int err = pthread_create(&th, NULL, stdin_reader_thread, NULL);
256
257         if(err) {
258                 fprintf(stderr, "Could not start reader thread: %s\n", strerror(err));
259                 goto server_err;
260         }
261
262         int client_fd = socket(AF_INET, SOCK_STREAM, 0);
263
264         if(client_fd < 0) {
265                 fprintf(stderr, "Could not create client socket: %s\n", strerror(errno));
266                 return -1;
267         }
268
269         if(connect(client_fd, (struct sockaddr *)&connect_sa, sizeof(connect_sa)) < 0) {
270                 fprintf(stderr, "Could not connect: %s\n", strerror(errno));
271                 closesocket(client_fd);
272                 return -1;
273         }
274
275         return client_fd;
276
277 server_err:
278
279         if(stdin_sock_fd != -1) {
280                 closesocket(stdin_sock_fd);
281                 stdin_sock_fd = -1;
282         }
283
284         return -1;
285 }
286
287 #endif // HAVE_MINGW
288
289 int main(int argc, char *argv[]) {
290         program_name = argv[0];
291         bool initiator = false;
292         bool datagram = false;
293 #ifdef HAVE_LINUX
294         bool tun = false;
295 #endif
296         int packetloss = 0;
297         int r;
298         int option_index = 0;
299         ecdsa_t *mykey = NULL, *hiskey = NULL;
300         bool quit = false;
301
302         while((r = getopt_long(argc, argv, "dqrstwL:W:v46", long_options, &option_index)) != EOF) {
303                 switch(r) {
304                 case 0:   /* long option */
305                         break;
306
307                 case 'd': /* datagram mode */
308                         datagram = true;
309                         break;
310
311                 case 'q': /* close connection on EOF from stdin */
312                         quit = true;
313                         break;
314
315                 case 'r': /* read only */
316                         readonly = true;
317                         break;
318
319                 case 't': /* read only */
320 #ifdef HAVE_LINUX
321                         tun = true;
322 #else
323                         fprintf(stderr, "--tun is only supported on Linux.\n");
324                         usage();
325                         return 1;
326 #endif
327                         break;
328
329                 case 'w': /* write only */
330                         writeonly = true;
331                         break;
332
333                 case 'L': /* packet loss rate */
334                         packetloss = atoi(optarg);
335                         break;
336
337                 case 'W': /* replay window size */
338                         sptps_replaywin = atoi(optarg);
339                         break;
340
341                 case 'v': /* be verbose */
342                         verbose = true;
343                         break;
344
345                 case 's': /* special character handling */
346                         special = true;
347                         break;
348
349                 case '?': /* wrong options */
350                         usage();
351                         return 1;
352
353                 case '4': /* IPv4 */
354                         addressfamily = AF_INET;
355                         break;
356
357                 case '6': /* IPv6 */
358                         addressfamily = AF_INET6;
359                         break;
360
361                 case 1: /* help */
362                         usage();
363                         return 0;
364
365                 default:
366                         break;
367                 }
368         }
369
370         argc -= optind - 1;
371         argv += optind - 1;
372
373         if(argc < 4 || argc > 5) {
374                 fprintf(stderr, "Wrong number of arguments.\n");
375                 usage();
376                 return 1;
377         }
378
379         if(argc > 4) {
380                 initiator = true;
381         }
382
383         srand(getpid());
384
385 #ifdef HAVE_LINUX
386
387         if(tun) {
388                 in = out = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
389
390                 if(in < 0) {
391                         fprintf(stderr, "Could not open tun device: %s\n", strerror(errno));
392                         return 1;
393                 }
394
395                 struct ifreq ifr = {
396                         .ifr_flags = IFF_TUN
397                 };
398
399                 if(ioctl(in, TUNSETIFF, &ifr)) {
400                         fprintf(stderr, "Could not configure tun interface: %s\n", strerror(errno));
401                         return 1;
402                 }
403
404                 ifr.ifr_name[IFNAMSIZ - 1] = 0;
405                 fprintf(stderr, "Using tun interface %s\n", ifr.ifr_name);
406         }
407
408 #endif
409
410 #ifdef HAVE_MINGW
411         static struct WSAData wsa_state;
412
413         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
414                 return 1;
415         }
416
417 #endif
418
419         struct addrinfo *ai, hint;
420         memset(&hint, 0, sizeof(hint));
421
422         hint.ai_family = addressfamily;
423         hint.ai_socktype = datagram ? SOCK_DGRAM : SOCK_STREAM;
424         hint.ai_protocol = datagram ? IPPROTO_UDP : IPPROTO_TCP;
425         hint.ai_flags = initiator ? 0 : AI_PASSIVE;
426
427         if(getaddrinfo(initiator ? argv[3] : NULL, initiator ? argv[4] : argv[3], &hint, &ai) || !ai) {
428                 fprintf(stderr, "getaddrinfo() failed: %s\n", sockstrerror(sockerrno));
429                 return 1;
430         }
431
432         int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
433
434         if(sock < 0) {
435                 fprintf(stderr, "Could not create socket: %s\n", sockstrerror(sockerrno));
436                 return 1;
437         }
438
439         int one = 1;
440         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
441
442         if(initiator) {
443                 if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
444                         fprintf(stderr, "Could not connect to peer: %s\n", sockstrerror(sockerrno));
445                         return 1;
446                 }
447
448                 fprintf(stderr, "Connected\n");
449         } else {
450                 if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
451                         fprintf(stderr, "Could not bind socket: %s\n", sockstrerror(sockerrno));
452                         return 1;
453                 }
454
455                 if(!datagram) {
456                         if(listen(sock, 1)) {
457                                 fprintf(stderr, "Could not listen on socket: %s\n", sockstrerror(sockerrno));
458                                 return 1;
459                         }
460
461                         fprintf(stderr, "Listening...\n");
462
463                         sock = accept(sock, NULL, NULL);
464
465                         if(sock < 0) {
466                                 fprintf(stderr, "Could not accept connection: %s\n", sockstrerror(sockerrno));
467                                 return 1;
468                         }
469                 } else {
470                         fprintf(stderr, "Listening...\n");
471
472                         char buf[65536];
473                         struct sockaddr addr;
474                         socklen_t addrlen = sizeof(addr);
475
476                         if(recvfrom(sock, buf, sizeof(buf), MSG_PEEK, &addr, &addrlen) <= 0) {
477                                 fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
478                                 return 1;
479                         }
480
481                         if(connect(sock, &addr, addrlen)) {
482                                 fprintf(stderr, "Could not accept connection: %s\n", sockstrerror(sockerrno));
483                                 return 1;
484                         }
485                 }
486
487                 fprintf(stderr, "Connected\n");
488         }
489
490         crypto_init();
491
492         FILE *fp = fopen(argv[1], "r");
493
494         if(!fp) {
495                 fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
496                 return 1;
497         }
498
499         if(!(mykey = ecdsa_read_pem_private_key(fp))) {
500                 return 1;
501         }
502
503         fclose(fp);
504
505         fp = fopen(argv[2], "r");
506
507         if(!fp) {
508                 fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
509                 return 1;
510         }
511
512         if(!(hiskey = ecdsa_read_pem_public_key(fp))) {
513                 return 1;
514         }
515
516         fclose(fp);
517
518         if(verbose) {
519                 fprintf(stderr, "Keys loaded\n");
520         }
521
522         sptps_t s;
523
524         if(!sptps_start(&s, &sock, initiator, datagram, mykey, hiskey, "sptps_test", 10, send_data, receive_record)) {
525                 return 1;
526         }
527
528 #ifdef HAVE_MINGW
529
530         if(!readonly) {
531                 in = start_input_reader();
532
533                 if(in < 0) {
534                         fprintf(stderr, "Could not init stdin reader thread\n");
535                         return 1;
536                 }
537         }
538
539 #endif
540
541         int max_fd = MAX(sock, in);
542
543         while(true) {
544                 if(writeonly && readonly) {
545                         break;
546                 }
547
548                 char buf[65535] = "";
549                 size_t readsize = datagram ? 1460u : sizeof(buf);
550
551                 fd_set fds;
552                 FD_ZERO(&fds);
553
554                 if(!readonly && s.instate) {
555                         FD_SET(in, &fds);
556                 }
557
558                 FD_SET(sock, &fds);
559
560                 if(select(max_fd + 1, &fds, NULL, NULL, NULL) <= 0) {
561                         return 1;
562                 }
563
564                 if(FD_ISSET(in, &fds)) {
565 #ifdef HAVE_MINGW
566                         ssize_t len = recv(in, buf, readsize, 0);
567 #else
568                         ssize_t len = read(in, buf, readsize);
569 #endif
570
571                         if(len < 0) {
572                                 fprintf(stderr, "Could not read from stdin: %s\n", strerror(errno));
573                                 return 1;
574                         }
575
576                         if(len == 0) {
577 #ifdef HAVE_MINGW
578                                 shutdown(in, SD_SEND);
579                                 closesocket(in);
580 #endif
581
582                                 if(quit) {
583                                         break;
584                                 }
585
586                                 readonly = true;
587                                 continue;
588                         }
589
590                         if(special && buf[0] == '#') {
591                                 s.outseqno = atoi(buf + 1);
592                         }
593
594                         if(special && buf[0] == '^') {
595                                 sptps_send_record(&s, SPTPS_HANDSHAKE, NULL, 0);
596                         } else if(special && buf[0] == '$') {
597                                 sptps_force_kex(&s);
598
599                                 if(len > 1) {
600                                         sptps_send_record(&s, 0, buf, len);
601                                 }
602                         } else if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof(buf) : (size_t)len)) {
603                                 return 1;
604                         }
605                 }
606
607                 if(FD_ISSET(sock, &fds)) {
608                         ssize_t len = recv(sock, buf, sizeof(buf), 0);
609
610                         if(len < 0) {
611                                 fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
612                                 return 1;
613                         }
614
615                         if(len == 0) {
616                                 fprintf(stderr, "Connection terminated by peer.\n");
617                                 break;
618                         }
619
620                         if(verbose) {
621                                 char hex[len * 2 + 1];
622                                 bin2hex(buf, hex, len);
623                                 fprintf(stderr, "Received %d bytes of data:\n%s\n", (int)len, hex);
624                         }
625
626                         if(packetloss && (rand() % 100) < packetloss) {
627                                 if(verbose) {
628                                         fprintf(stderr, "Dropped.\n");
629                                 }
630
631                                 continue;
632                         }
633
634                         char *bufp = buf;
635
636                         while(len) {
637                                 size_t done = sptps_receive_data(&s, bufp, len);
638
639                                 if(!done) {
640                                         if(!datagram) {
641                                                 return 1;
642                                         }
643                                 }
644
645                                 bufp += done;
646                                 len -= done;
647                         }
648                 }
649         }
650
651         if(!sptps_stop(&s)) {
652                 return 1;
653         }
654
655         closesocket(sock);
656
657         return 0;
658 }