warp.c (3758B)
1 /* 2 * Design overview: 3 * 4 * warp-vpn implements a point to point encrypted tunnel. It supports 5 * layer 2 (TAP) and layer 3 (TUN) tunnels. TCP is the only supported 6 * transport. 7 * 8 * warp-vpn is a client-server design. There can only be a single client 9 * connected to the server at any time. Routing between clients is handled 10 * by the networking stack on the server side. 11 * 12 * When a client connects there is a mutual challenge-response phase 13 * as shown below: 14 * 15 * t0: server challenges client 16 * t1: client responds to server's challenge 17 * t2: client challenges server 18 * t3: server responds to client's challenge 19 * 20 * The challenge-response algorithm is as follows: 21 * 22 * The challenge is a randomly generated 64-bit integer encrypted 23 * with the pre-shared key and sent to the receiver. 24 * The receiver decrypts it, adds 1, encrypts it and sends it back to 25 * the sender. The sender verifies the response. 26 * This algorithm is the same as what Kerberos uses for authentication. 27 * 28 * The warp-vpn packet format is shown below: 29 * 30 * [NONCE] [PAYLOAD LEN] [PAYLOAD] [TAG] 31 */ 32 33 #include <sys/resource.h> 34 35 #include <signal.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "arg.h" 42 #include "warp.h" 43 44 char *argv0; 45 char *bindaddr; 46 char *host; 47 char *port = DEFPORT; 48 int devtype = TUNDEV; 49 int aftype = AF_INET; 50 int sflag; 51 52 void 53 usage(void) 54 { 55 fprintf(stderr, "usage: warp-vpn [-46] [-d] -s [-b address] [-p port] [-t devtype] [-u user] interface\n"); 56 fprintf(stderr, " warp-vpn [-46] [-d] -h host [-p port] [-t devtype] [-u user] interface\n"); 57 exit(1); 58 } 59 60 int 61 main(int argc, char *argv[]) 62 { 63 struct rlimit rlim; 64 char *arg, *pw; 65 char *user = NOPRIVUSER; 66 int devfd, listenfd, netfd; 67 68 ARGBEGIN { 69 case '4': 70 aftype = AF_INET; 71 break; 72 case '6': 73 aftype = AF_INET6; 74 break; 75 case 'd': 76 debug = 1; 77 break; 78 case 's': 79 sflag = 1; 80 break; 81 case 'b': 82 bindaddr = EARGF(usage()); 83 break; 84 case 'h': 85 host = EARGF(usage()); 86 break; 87 case 'p': 88 port = EARGF(usage()); 89 break; 90 case 't': 91 arg = EARGF(usage()); 92 if (strcasecmp(arg, "tun") == 0) 93 devtype = TUNDEV; 94 else if (strcasecmp(arg, "tap") == 0) 95 devtype = TAPDEV; 96 else 97 usage(); 98 break; 99 case 'u': 100 user = EARGF(usage()); 101 break; 102 default: 103 usage(); 104 } ARGEND 105 106 if (argc != 1 || !(sflag ^ (host != NULL))) 107 usage(); 108 109 loginit("warp-vpn"); 110 111 /* disable core dumps as memory contains the pre-shared key */ 112 rlim.rlim_cur = rlim.rlim_max = 0; 113 if (setrlimit(RLIMIT_CORE, &rlim) < 0) 114 fatalx("failed to disable core dumps"); 115 116 signal(SIGPIPE, SIG_IGN); 117 if (!debug) 118 daemon(0, 0); 119 120 /* initialize tun/tap device */ 121 devfd = devopen(argv[0]); 122 123 /* initialize crypto engine */ 124 if (!(pw = getenv("PW"))) 125 fatalx("PW is not set"); 126 cryptoinit(); 127 derivekey(pw); 128 memset(pw, 0, strlen(pw)); 129 130 /* initialize networking engine */ 131 netinit(); 132 133 if (sflag) { 134 /* invoked as server */ 135 listenfd = serverinit(bindaddr, port); 136 revokeprivs(user); 137 if (mypledge("stdio inet", NULL) < 0) 138 fatal("pledge"); 139 for (;;) { 140 if ((netfd = serveraccept(listenfd)) < 0) { 141 netreset(); 142 continue; 143 } 144 logdbgx("client %s is ready", peer_ntop(netfd)); 145 tunnel(netfd, devfd); 146 logdbgx("client %s disconnected", peer_ntop(netfd)); 147 close(netfd); 148 netreset(); 149 } 150 } else { 151 /* invoked as client */ 152 revokeprivs(user); 153 if (mypledge("stdio dns inet", NULL) < 0) 154 fatal("pledge"); 155 for (;;) { 156 if ((netfd = clientconnect(host, port)) < 0) { 157 netreset(); 158 sleep(RECONNECTTIMEO); 159 continue; 160 } 161 logdbgx("connected to %s", peer_ntop(netfd)); 162 tunnel(netfd, devfd); 163 logdbgx("disconnected from %s", peer_ntop(netfd)); 164 close(netfd); 165 netreset(); 166 sleep(RECONNECTTIMEO); 167 } 168 } 169 return 0; 170 }