GitHub CI: update list of container images
[tinc] / src / sptps_test.c
index 5e785b3..38e8b50 100644 (file)
@@ -1,6 +1,6 @@
 /*
     sptps_test.c -- Simple Peer-to-Peer Security test program
-    Copyright (C) 2011-2014 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2011-2022 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include <linux/if_tun.h>
 #endif
 
-#include <getopt.h>
-
-#ifdef HAVE_MINGW
-#include <pthread.h>
-#endif
-
 #include "crypto.h"
 #include "ecdsa.h"
+#include "meta.h"
+#include "protocol.h"
 #include "sptps.h"
 #include "utils.h"
+#include "names.h"
+#include "random.h"
 
-#ifndef HAVE_MINGW
+#ifndef HAVE_WINDOWS
 #define closesocket(s) close(s)
 #endif
 
 // Symbols necessary to link with logger.o
-bool send_request(void *c, const char *msg, ...) {
+bool send_request(struct connection_t *c, const char *msg, ...) {
        (void)c;
        (void)msg;
        return false;
 }
 
-struct list_t *connection_list = NULL;
+list_t connection_list;
 
-bool send_meta(void *c, const char *msg, int len) {
+bool send_meta(struct connection_t *c, const void *msg, size_t len) {
        (void)c;
        (void)msg;
        (void)len;
        return false;
 }
 
-char *logfilename = NULL;
 bool do_detach = false;
 struct timeval now;
 
@@ -64,21 +61,30 @@ static bool readonly;
 static bool writeonly;
 static int in = 0;
 static int out = 1;
-static int addressfamily = AF_UNSPEC;
+int addressfamily = AF_UNSPEC;
 
 static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
        (void)type;
-       char hex[len * 2 + 1];
+       char *hex = alloca(len * 2 + 1);
        bin2hex(data, hex, len);
 
        if(verbose) {
-               fprintf(stderr, "Sending %zu bytes of data:\n%s\n", len, hex);
+               fprintf(stderr, "Sending %lu bytes of data:\n%s\n", (unsigned long)len, hex);
        }
 
        const int *sock = handle;
+       const char *p = data;
+
+       while(len) {
+               ssize_t sent = send(*sock, p, len, 0);
+
+               if(sent <= 0) {
+                       fprintf(stderr, "Error sending data: %s\n", strerror(errno));
+                       return false;
+               }
 
-       if((size_t)send(*sock, data, len, 0) != len) {
-               return false;
+               p += sent;
+               len -= sent;
        }
 
        return true;
@@ -91,31 +97,67 @@ static bool receive_record(void *handle, uint8_t type, const void *data, uint16_
                fprintf(stderr, "Received type %d record of %u bytes:\n", type, len);
        }
 
-       if(!writeonly) {
-               write(out, data, len);
+       if(writeonly) {
+               return true;
+       }
+
+       const char *p = data;
+
+       while(len) {
+               ssize_t written = write(out, p, len);
+
+               if(written <= 0) {
+                       fprintf(stderr, "Error writing received data: %s\n", strerror(errno));
+                       return false;
+               }
+
+               p += written;
+               len -= written;
        }
 
        return true;
 }
 
+typedef enum option_t {
+       OPT_BAD_OPTION    = '?',
+       OPT_LONG_OPTION   =  0,
+
+       // Short options
+       OPT_DATAGRAM      = 'd',
+       OPT_QUIT_ON_EOF   = 'q',
+       OPT_READONLY      = 'r',
+       OPT_WRITEONLY     = 'w',
+       OPT_PACKET_LOSS   = 'L',
+       OPT_REPLAY_WINDOW = 'W',
+       OPT_SPECIAL_CHAR  = 's',
+       OPT_TUN           = 't',
+       OPT_VERBOSE       = 'v',
+       OPT_IPV4          = '4',
+       OPT_IPV6          = '6',
+
+       // Long options
+       OPT_HELP          = 255,
+} option_t;
+
 static struct option const long_options[] = {
-       {"datagram", no_argument, NULL, 'd'},
-       {"quit", no_argument, NULL, 'q'},
-       {"readonly", no_argument, NULL, 'r'},
-       {"writeonly", no_argument, NULL, 'w'},
-       {"packet-loss", required_argument, NULL, 'L'},
-       {"replay-window", required_argument, NULL, 'W'},
-       {"special", no_argument, NULL, 's'},
-       {"verbose", required_argument, NULL, 'v'},
-       {"help", no_argument, NULL, 1},
-       {NULL, 0, NULL, 0}
+       {"datagram",      no_argument,       NULL, OPT_DATAGRAM},
+       {"quit",          no_argument,       NULL, OPT_QUIT_ON_EOF},
+       {"readonly",      no_argument,       NULL, OPT_READONLY},
+       {"writeonly",     no_argument,       NULL, OPT_WRITEONLY},
+       {"packet-loss",   required_argument, NULL, OPT_PACKET_LOSS},
+       {"replay-window", required_argument, NULL, OPT_REPLAY_WINDOW},
+       {"special",       no_argument,       NULL, OPT_SPECIAL_CHAR},
+       {"tun",           no_argument,       NULL, OPT_TUN},
+       {"verbose",       required_argument, NULL, OPT_VERBOSE},
+       {"help",          no_argument,       NULL, OPT_HELP},
+       {NULL,            0,                 NULL, 0}
 };
 
-const char *program_name;
-
-static void usage() {
-       fprintf(stderr, "Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n\n", program_name);
-       fprintf(stderr, "Valid options are:\n"
+static void usage(void) {
+       fprintf(stderr,
+               "Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n"
+               "\n"
+               "Valid options are:\n"
                "  -d, --datagram          Enable datagram mode.\n"
                "  -q, --quit              Quit when EOF occurs on stdin.\n"
                "  -r, --readonly          Only send data from the socket to stdout.\n"
@@ -129,11 +171,12 @@ static void usage() {
                "  -v, --verbose           Display debug messages.\n"
                "  -4                      Use IPv4.\n"
                "  -6                      Use IPv6.\n"
-               "\n");
-       fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
+               "\n"
+               "Report bugs to tinc@tinc-vpn.org.\n",
+               program_name);
 }
 
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
 
 int stdin_sock_fd = -1;
 
@@ -142,7 +185,7 @@ int stdin_sock_fd = -1;
 // separate thread between the stdin and the sptps loop way below. This thread
 // reads stdin and sends its content to the main thread through a TCP socket,
 // which can be properly select()'ed.
-void *stdin_reader_thread(void *arg) {
+static DWORD WINAPI stdin_reader_thread(LPVOID arg) {
        struct sockaddr_in sa;
        socklen_t sa_size = sizeof(sa);
 
@@ -158,7 +201,7 @@ void *stdin_reader_thread(void *arg) {
                        fprintf(stderr, "New connection received from :%d\n", ntohs(sa.sin_port));
                }
 
-               uint8_t buf[1024];
+               char buf[1024];
                ssize_t nread;
 
                while((nread = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
@@ -166,7 +209,7 @@ void *stdin_reader_thread(void *arg) {
                                fprintf(stderr, "Read %lld bytes from input\n", nread);
                        }
 
-                       uint8_t *start = buf;
+                       char *start = buf;
                        ssize_t nleft = nread;
 
                        while(nleft) {
@@ -199,9 +242,10 @@ void *stdin_reader_thread(void *arg) {
 
        closesocket(stdin_sock_fd);
        stdin_sock_fd = -1;
+       return 0;
 }
 
-int start_input_reader() {
+static int start_input_reader(void) {
        if(stdin_sock_fd != -1) {
                fprintf(stderr, "stdin thread can only be started once.\n");
                return -1;
@@ -247,11 +291,8 @@ int start_input_reader() {
                fprintf(stderr, "stdin thread is listening on :%d\n", ntohs(connect_sa.sin_port));
        }
 
-       pthread_t th;
-       int err = pthread_create(&th, NULL, stdin_reader_thread, NULL);
-
-       if(err) {
-               fprintf(stderr, "Could not start reader thread: %s\n", strerror(err));
+       if(!CreateThread(NULL, 0, stdin_reader_thread, NULL, 0, NULL)) {
+               fprintf(stderr, "Could not start reader thread: %d\n", GetLastError());
                goto server_err;
        }
 
@@ -280,9 +321,22 @@ server_err:
        return -1;
 }
 
-#endif // HAVE_MINGW
+#endif // HAVE_WINDOWS
 
-int main(int argc, char *argv[]) {
+static void print_listening_msg(int sock) {
+       sockaddr_t sa = {0};
+       socklen_t salen = sizeof(sa);
+       int port = 0;
+
+       if(!getsockname(sock, &sa.sa, &salen)) {
+               port = ntohs(sa.in.sin_port);
+       }
+
+       fprintf(stderr, "Listening on %d...\n", port);
+       fflush(stderr);
+}
+
+static int run_test(int argc, char *argv[]) {
        program_name = argv[0];
        bool initiator = false;
        bool datagram = false;
@@ -295,23 +349,27 @@ int main(int argc, char *argv[]) {
        bool quit = false;
 
        while((r = getopt_long(argc, argv, "dqrstwL:W:v46", long_options, &option_index)) != EOF) {
-               switch(r) {
-               case 0:   /* long option */
+               switch((option_t) r) {
+               case OPT_LONG_OPTION:
                        break;
 
-               case 'd': /* datagram mode */
+               case OPT_BAD_OPTION:
+                       usage();
+                       return 1;
+
+               case OPT_DATAGRAM:
                        datagram = true;
                        break;
 
-               case 'q': /* close connection on EOF from stdin */
+               case OPT_QUIT_ON_EOF:
                        quit = true;
                        break;
 
-               case 'r': /* read only */
+               case OPT_READONLY:
                        readonly = true;
                        break;
 
-               case 't': /* read only */
+               case OPT_TUN:
 #ifdef HAVE_LINUX
                        tun = true;
 #else
@@ -321,39 +379,35 @@ int main(int argc, char *argv[]) {
 #endif
                        break;
 
-               case 'w': /* write only */
+               case OPT_WRITEONLY:
                        writeonly = true;
                        break;
 
-               case 'L': /* packet loss rate */
+               case OPT_PACKET_LOSS:
                        packetloss = atoi(optarg);
                        break;
 
-               case 'W': /* replay window size */
+               case OPT_REPLAY_WINDOW:
                        sptps_replaywin = atoi(optarg);
                        break;
 
-               case 'v': /* be verbose */
+               case OPT_VERBOSE:
                        verbose = true;
                        break;
 
-               case 's': /* special character handling */
+               case OPT_SPECIAL_CHAR:
                        special = true;
                        break;
 
-               case '?': /* wrong options */
-                       usage();
-                       return 1;
-
-               case '4': /* IPv4 */
+               case OPT_IPV4:
                        addressfamily = AF_INET;
                        break;
 
-               case '6': /* IPv6 */
+               case OPT_IPV6:
                        addressfamily = AF_INET6;
                        break;
 
-               case 1: /* help */
+               case OPT_HELP:
                        usage();
                        return 0;
 
@@ -375,8 +429,6 @@ int main(int argc, char *argv[]) {
                initiator = true;
        }
 
-       srand(getpid());
-
 #ifdef HAVE_LINUX
 
        if(tun) {
@@ -402,7 +454,7 @@ int main(int argc, char *argv[]) {
 
 #endif
 
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
        static struct WSAData wsa_state;
 
        if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
@@ -464,7 +516,7 @@ int main(int argc, char *argv[]) {
                                return 1;
                        }
 
-                       fprintf(stderr, "Listening...\n");
+                       print_listening_msg(sock);
 
                        sock = accept(sock, NULL, NULL);
 
@@ -473,9 +525,9 @@ int main(int argc, char *argv[]) {
                                return 1;
                        }
                } else {
-                       fprintf(stderr, "Listening...\n");
+                       print_listening_msg(sock);
 
-                       uint8_t buf[65536];
+                       char buf[65536];
                        struct sockaddr addr;
                        socklen_t addrlen = sizeof(addr);
 
@@ -493,8 +545,6 @@ int main(int argc, char *argv[]) {
                fprintf(stderr, "Connected\n");
        }
 
-       crypto_init();
-
        FILE *fp = fopen(argv[1], "r");
 
        if(!fp) {
@@ -514,14 +564,14 @@ int main(int argc, char *argv[]) {
 
        if(!fp) {
                fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
-               free(mykey);
+               ecdsa_free(mykey);
                return 1;
        }
 
        ecdsa_t *hiskey = NULL;
 
        if(!(hiskey = ecdsa_read_pem_public_key(fp))) {
-               free(mykey);
+               ecdsa_free(mykey);
                return 1;
        }
 
@@ -534,20 +584,20 @@ int main(int argc, char *argv[]) {
        sptps_t s;
 
        if(!sptps_start(&s, &sock, initiator, datagram, mykey, hiskey, "sptps_test", 10, send_data, receive_record)) {
-               free(mykey);
-               free(hiskey);
+               ecdsa_free(mykey);
+               ecdsa_free(hiskey);
                return 1;
        }
 
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
 
        if(!readonly) {
                in = start_input_reader();
 
                if(in < 0) {
                        fprintf(stderr, "Could not init stdin reader thread\n");
-                       free(mykey);
-                       free(hiskey);
+                       ecdsa_free(mykey);
+                       ecdsa_free(hiskey);
                        return 1;
                }
        }
@@ -574,13 +624,13 @@ int main(int argc, char *argv[]) {
                FD_SET(sock, &fds);
 
                if(select(max_fd + 1, &fds, NULL, NULL, NULL) <= 0) {
-                       free(mykey);
-                       free(hiskey);
+                       ecdsa_free(mykey);
+                       ecdsa_free(hiskey);
                        return 1;
                }
 
                if(FD_ISSET(in, &fds)) {
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
                        ssize_t len = recv(in, buf, readsize, 0);
 #else
                        ssize_t len = read(in, buf, readsize);
@@ -588,13 +638,13 @@ int main(int argc, char *argv[]) {
 
                        if(len < 0) {
                                fprintf(stderr, "Could not read from stdin: %s\n", strerror(errno));
-                               free(mykey);
-                               free(hiskey);
+                               ecdsa_free(mykey);
+                               ecdsa_free(hiskey);
                                return 1;
                        }
 
                        if(len == 0) {
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
                                shutdown(in, SD_SEND);
                                closesocket(in);
 #endif
@@ -620,8 +670,8 @@ int main(int argc, char *argv[]) {
                                        sptps_send_record(&s, 0, buf, len);
                                }
                        } else if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof(buf) : (size_t)len)) {
-                               free(mykey);
-                               free(hiskey);
+                               ecdsa_free(mykey);
+                               ecdsa_free(hiskey);
                                return 1;
                        }
                }
@@ -631,8 +681,8 @@ int main(int argc, char *argv[]) {
 
                        if(len < 0) {
                                fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
-                               free(mykey);
-                               free(hiskey);
+                               ecdsa_free(mykey);
+                               ecdsa_free(hiskey);
                                return 1;
                        }
 
@@ -642,12 +692,12 @@ int main(int argc, char *argv[]) {
                        }
 
                        if(verbose) {
-                               char hex[len * 2 + 1];
+                               char *hex = alloca(len * 2 + 1);
                                bin2hex(buf, hex, len);
-                               fprintf(stderr, "Received %zd bytes of data:\n%s\n", len, hex);
+                               fprintf(stderr, "Received %ld bytes of data:\n%s\n", (long)len, hex);
                        }
 
-                       if(packetloss && (rand() % 100) < packetloss) {
+                       if(packetloss && (int)prng(100) < packetloss) {
                                if(verbose) {
                                        fprintf(stderr, "Dropped.\n");
                                }
@@ -662,8 +712,8 @@ int main(int argc, char *argv[]) {
 
                                if(!done) {
                                        if(!datagram) {
-                                               free(mykey);
-                                               free(hiskey);
+                                               ecdsa_free(mykey);
+                                               ecdsa_free(hiskey);
                                                return 1;
                                        }
                                }
@@ -676,14 +726,21 @@ int main(int argc, char *argv[]) {
 
        bool stopped = sptps_stop(&s);
 
-       free(mykey);
-       free(hiskey);
+       ecdsa_free(mykey);
+       ecdsa_free(hiskey);
+       closesocket(sock);
 
-       if(!stopped) {
-               return 1;
-       }
+       return !stopped;
+}
 
-       closesocket(sock);
+int main(int argc, char *argv[]) {
+       random_init();
+       crypto_init();
+       prng_init();
 
-       return 0;
+       int result = run_test(argc, argv);
+
+       random_exit();
+
+       return result;
 }