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