64b8cb22d24664687df5abff53d4141bcc59b6bd
[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         bool quit = false;
300
301         while((r = getopt_long(argc, argv, "dqrstwL:W:v46", long_options, &option_index)) != EOF) {
302                 switch(r) {
303                 case 0:   /* long option */
304                         break;
305
306                 case 'd': /* datagram mode */
307                         datagram = true;
308                         break;
309
310                 case 'q': /* close connection on EOF from stdin */
311                         quit = true;
312                         break;
313
314                 case 'r': /* read only */
315                         readonly = true;
316                         break;
317
318                 case 't': /* read only */
319 #ifdef HAVE_LINUX
320                         tun = true;
321 #else
322                         fprintf(stderr, "--tun is only supported on Linux.\n");
323                         usage();
324                         return 1;
325 #endif
326                         break;
327
328                 case 'w': /* write only */
329                         writeonly = true;
330                         break;
331
332                 case 'L': /* packet loss rate */
333                         packetloss = atoi(optarg);
334                         break;
335
336                 case 'W': /* replay window size */
337                         sptps_replaywin = atoi(optarg);
338                         break;
339
340                 case 'v': /* be verbose */
341                         verbose = true;
342                         break;
343
344                 case 's': /* special character handling */
345                         special = true;
346                         break;
347
348                 case '?': /* wrong options */
349                         usage();
350                         return 1;
351
352                 case '4': /* IPv4 */
353                         addressfamily = AF_INET;
354                         break;
355
356                 case '6': /* IPv6 */
357                         addressfamily = AF_INET6;
358                         break;
359
360                 case 1: /* help */
361                         usage();
362                         return 0;
363
364                 default:
365                         break;
366                 }
367         }
368
369         argc -= optind - 1;
370         argv += optind - 1;
371
372         if(argc < 4 || argc > 5) {
373                 fprintf(stderr, "Wrong number of arguments.\n");
374                 usage();
375                 return 1;
376         }
377
378         if(argc > 4) {
379                 initiator = true;
380         }
381
382         srand(getpid());
383
384 #ifdef HAVE_LINUX
385
386         if(tun) {
387                 in = out = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
388
389                 if(in < 0) {
390                         fprintf(stderr, "Could not open tun device: %s\n", strerror(errno));
391                         return 1;
392                 }
393
394                 struct ifreq ifr = {
395                         .ifr_flags = IFF_TUN
396                 };
397
398                 if(ioctl(in, TUNSETIFF, &ifr)) {
399                         fprintf(stderr, "Could not configure tun interface: %s\n", strerror(errno));
400                         return 1;
401                 }
402
403                 ifr.ifr_name[IFNAMSIZ - 1] = 0;
404                 fprintf(stderr, "Using tun interface %s\n", ifr.ifr_name);
405         }
406
407 #endif
408
409 #ifdef HAVE_MINGW
410         static struct WSAData wsa_state;
411
412         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
413                 return 1;
414         }
415
416 #endif
417
418         struct addrinfo *ai, hint;
419         memset(&hint, 0, sizeof(hint));
420
421         hint.ai_family = addressfamily;
422         hint.ai_socktype = datagram ? SOCK_DGRAM : SOCK_STREAM;
423         hint.ai_protocol = datagram ? IPPROTO_UDP : IPPROTO_TCP;
424         hint.ai_flags = initiator ? 0 : AI_PASSIVE;
425
426         if(getaddrinfo(initiator ? argv[3] : NULL, initiator ? argv[4] : argv[3], &hint, &ai) || !ai) {
427                 fprintf(stderr, "getaddrinfo() failed: %s\n", sockstrerror(sockerrno));
428                 return 1;
429         }
430
431         int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
432
433         if(sock < 0) {
434                 fprintf(stderr, "Could not create socket: %s\n", sockstrerror(sockerrno));
435                 freeaddrinfo(ai);
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                 int res = connect(sock, ai->ai_addr, ai->ai_addrlen);
444
445                 freeaddrinfo(ai);
446                 ai = NULL;
447
448                 if(res) {
449                         fprintf(stderr, "Could not connect to peer: %s\n", sockstrerror(sockerrno));
450                         return 1;
451                 }
452
453                 fprintf(stderr, "Connected\n");
454         } else {
455                 int res = bind(sock, ai->ai_addr, ai->ai_addrlen);
456
457                 freeaddrinfo(ai);
458                 ai = NULL;
459
460                 if(res) {
461                         fprintf(stderr, "Could not bind socket: %s\n", sockstrerror(sockerrno));
462                         return 1;
463                 }
464
465                 if(!datagram) {
466                         if(listen(sock, 1)) {
467                                 fprintf(stderr, "Could not listen on socket: %s\n", sockstrerror(sockerrno));
468                                 return 1;
469                         }
470
471                         fprintf(stderr, "Listening...\n");
472
473                         sock = accept(sock, NULL, NULL);
474
475                         if(sock < 0) {
476                                 fprintf(stderr, "Could not accept connection: %s\n", sockstrerror(sockerrno));
477                                 return 1;
478                         }
479                 } else {
480                         fprintf(stderr, "Listening...\n");
481
482                         char buf[65536];
483                         struct sockaddr addr;
484                         socklen_t addrlen = sizeof(addr);
485
486                         if(recvfrom(sock, buf, sizeof(buf), MSG_PEEK, &addr, &addrlen) <= 0) {
487                                 fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
488                                 return 1;
489                         }
490
491                         if(connect(sock, &addr, addrlen)) {
492                                 fprintf(stderr, "Could not accept connection: %s\n", sockstrerror(sockerrno));
493                                 return 1;
494                         }
495                 }
496
497                 fprintf(stderr, "Connected\n");
498         }
499
500         crypto_init();
501
502         FILE *fp = fopen(argv[1], "r");
503
504         if(!fp) {
505                 fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
506                 return 1;
507         }
508
509         ecdsa_t *mykey = NULL;
510
511         if(!(mykey = ecdsa_read_pem_private_key(fp))) {
512                 return 1;
513         }
514
515         fclose(fp);
516
517         fp = fopen(argv[2], "r");
518
519         if(!fp) {
520                 fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
521                 free(mykey);
522                 return 1;
523         }
524
525         ecdsa_t *hiskey = NULL;
526
527         if(!(hiskey = ecdsa_read_pem_public_key(fp))) {
528                 free(mykey);
529                 return 1;
530         }
531
532         fclose(fp);
533
534         if(verbose) {
535                 fprintf(stderr, "Keys loaded\n");
536         }
537
538         sptps_t s;
539
540         if(!sptps_start(&s, &sock, initiator, datagram, mykey, hiskey, "sptps_test", 10, send_data, receive_record)) {
541                 free(mykey);
542                 free(hiskey);
543                 return 1;
544         }
545
546 #ifdef HAVE_MINGW
547
548         if(!readonly) {
549                 in = start_input_reader();
550
551                 if(in < 0) {
552                         fprintf(stderr, "Could not init stdin reader thread\n");
553                         free(mykey);
554                         free(hiskey);
555                         return 1;
556                 }
557         }
558
559 #endif
560
561         int max_fd = MAX(sock, in);
562
563         while(true) {
564                 if(writeonly && readonly) {
565                         break;
566                 }
567
568                 char buf[65535] = "";
569                 size_t readsize = datagram ? 1460u : sizeof(buf);
570
571                 fd_set fds;
572                 FD_ZERO(&fds);
573
574                 if(!readonly && s.instate) {
575                         FD_SET(in, &fds);
576                 }
577
578                 FD_SET(sock, &fds);
579
580                 if(select(max_fd + 1, &fds, NULL, NULL, NULL) <= 0) {
581                         free(mykey);
582                         free(hiskey);
583                         return 1;
584                 }
585
586                 if(FD_ISSET(in, &fds)) {
587 #ifdef HAVE_MINGW
588                         ssize_t len = recv(in, buf, readsize, 0);
589 #else
590                         ssize_t len = read(in, buf, readsize);
591 #endif
592
593                         if(len < 0) {
594                                 fprintf(stderr, "Could not read from stdin: %s\n", strerror(errno));
595                                 free(mykey);
596                                 free(hiskey);
597                                 return 1;
598                         }
599
600                         if(len == 0) {
601 #ifdef HAVE_MINGW
602                                 shutdown(in, SD_SEND);
603                                 closesocket(in);
604 #endif
605
606                                 if(quit) {
607                                         break;
608                                 }
609
610                                 readonly = true;
611                                 continue;
612                         }
613
614                         if(special && buf[0] == '#') {
615                                 s.outseqno = atoi(buf + 1);
616                         }
617
618                         if(special && buf[0] == '^') {
619                                 sptps_send_record(&s, SPTPS_HANDSHAKE, NULL, 0);
620                         } else if(special && buf[0] == '$') {
621                                 sptps_force_kex(&s);
622
623                                 if(len > 1) {
624                                         sptps_send_record(&s, 0, buf, len);
625                                 }
626                         } else if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof(buf) : (size_t)len)) {
627                                 free(mykey);
628                                 free(hiskey);
629                                 return 1;
630                         }
631                 }
632
633                 if(FD_ISSET(sock, &fds)) {
634                         ssize_t len = recv(sock, buf, sizeof(buf), 0);
635
636                         if(len < 0) {
637                                 fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
638                                 free(mykey);
639                                 free(hiskey);
640                                 return 1;
641                         }
642
643                         if(len == 0) {
644                                 fprintf(stderr, "Connection terminated by peer.\n");
645                                 break;
646                         }
647
648                         if(verbose) {
649                                 char hex[len * 2 + 1];
650                                 bin2hex(buf, hex, len);
651                                 fprintf(stderr, "Received %d bytes of data:\n%s\n", (int)len, hex);
652                         }
653
654                         if(packetloss && (rand() % 100) < packetloss) {
655                                 if(verbose) {
656                                         fprintf(stderr, "Dropped.\n");
657                                 }
658
659                                 continue;
660                         }
661
662                         char *bufp = buf;
663
664                         while(len) {
665                                 size_t done = sptps_receive_data(&s, bufp, len);
666
667                                 if(!done) {
668                                         if(!datagram) {
669                                                 free(mykey);
670                                                 free(hiskey);
671                                                 return 1;
672                                         }
673                                 }
674
675                                 bufp += done;
676                                 len -= done;
677                         }
678                 }
679         }
680
681         bool stopped = sptps_stop(&s);
682
683         free(mykey);
684         free(hiskey);
685
686         if(!stopped) {
687                 return 1;
688         }
689
690         closesocket(sock);
691
692         return 0;
693 }