httpGate.c (7647B)
1 /* 04feb13abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <errno.h> 10 #include <ctype.h> 11 #include <string.h> 12 #include <signal.h> 13 #include <time.h> 14 #include <sys/time.h> 15 #include <sys/stat.h> 16 #include <netdb.h> 17 #include <arpa/inet.h> 18 #include <netinet/in.h> 19 #include <sys/socket.h> 20 21 #include <openssl/pem.h> 22 #include <openssl/ssl.h> 23 #include <openssl/err.h> 24 25 typedef enum {NO,YES} bool; 26 27 static int Http1; 28 29 static char Head_410[] = 30 "HTTP/1.0 410 Gone\r\n" 31 "Server: PicoLisp\r\n" 32 "Content-Type: text/html; charset=utf-8\r\n" 33 "\r\n"; 34 35 static void giveup(char *msg) { 36 fprintf(stderr, "httpGate: %s\n", msg); 37 exit(2); 38 } 39 40 static inline bool pre(char *p, char *s) { 41 while (*s) 42 if (*p++ != *s++) 43 return NO; 44 return YES; 45 } 46 47 static int slow(SSL *ssl, int fd, char *p, int cnt) { 48 int n; 49 50 while ((n = ssl? SSL_read(ssl, p, cnt) : read(fd, p, cnt)) < 0) 51 if (errno != EINTR) 52 return 0; 53 return n; 54 } 55 56 static int rdLine(SSL *ssl, int fd, char *p, int cnt) { 57 int n, len; 58 59 for (len = 0;;) { 60 if ((n = ssl? SSL_read(ssl, p, cnt) : read(fd, p, cnt)) <= 0) { 61 if (!n || errno != EINTR) 62 return 0; 63 } 64 else { 65 len += n; 66 if (memchr(p, '\n', n)) 67 return len; 68 p += n; 69 if ((cnt -= n) == 0) 70 return 0; 71 } 72 } 73 } 74 75 static void wrBytes(int fd, char *p, int cnt) { 76 int n; 77 78 do 79 if ((n = write(fd, p, cnt)) >= 0) 80 p += n, cnt -= n; 81 else if (errno != EINTR) 82 exit(1); 83 while (cnt); 84 } 85 86 static void sslWrite(SSL *ssl, void *p, int cnt) { 87 if (SSL_write(ssl, p, cnt) <= 0) 88 exit(1); 89 } 90 91 static int gatePort(unsigned short port) { 92 int sd, n; 93 struct sockaddr_in6 addr; 94 95 if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) 96 exit(1); 97 n = 0; 98 if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &n, sizeof(n)) < 0) 99 exit(1); 100 memset(&addr, 0, sizeof(addr)); 101 addr.sin6_family = AF_INET6; 102 addr.sin6_addr = in6addr_any; 103 n = 1; 104 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) < 0) 105 exit(1); 106 addr.sin6_port = htons(port); 107 if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 108 exit(1); 109 if (listen(sd,5) < 0) 110 exit(1); 111 return sd; 112 } 113 114 static int gateConnect(unsigned short port) { 115 int sd; 116 struct sockaddr_in6 addr; 117 118 if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) 119 exit(1); 120 memset(&addr, 0, sizeof(addr)); 121 addr.sin6_family = AF_INET6; 122 addr.sin6_addr = in6addr_loopback; 123 addr.sin6_port = htons(port); 124 return connect(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0? -1 : sd; 125 } 126 127 128 static pid_t Buddy; 129 130 static void doSigAlarm(int n __attribute__((unused))) { 131 kill(Buddy, SIGTERM); 132 exit(0); 133 } 134 135 static void doSigUsr1(int n __attribute__((unused))) { 136 alarm(420); 137 } 138 139 int main(int ac, char *av[]) { 140 int cnt = ac>4? ac-3 : 1, ports[cnt], n, sd, cli, srv; 141 struct sockaddr_in6 addr; 142 char s[INET6_ADDRSTRLEN]; 143 char *gate; 144 SSL_CTX *ctx; 145 SSL *ssl; 146 147 if (ac < 3) 148 giveup("port dflt [pem [alt ..]]"); 149 150 sd = gatePort(atoi(av[1])); // e.g. 80 or 443 151 ports[0] = atoi(av[2]); // e.g. 8080 152 if (ac == 3 || *av[3] == '\0') 153 ssl = NULL, gate = "X-Pil: *Gate=http\r\nX-Pil: *Adr=%s\r\n"; 154 else { 155 SSL_library_init(); 156 SSL_load_error_strings(); 157 if (!(ctx = SSL_CTX_new(SSLv23_server_method())) || 158 !SSL_CTX_use_certificate_file(ctx, av[3], SSL_FILETYPE_PEM) || 159 !SSL_CTX_use_PrivateKey_file(ctx, av[3], SSL_FILETYPE_PEM) || 160 !SSL_CTX_check_private_key(ctx) ) { 161 ERR_print_errors_fp(stderr); 162 giveup("SSL init"); 163 } 164 ssl = SSL_new(ctx), gate = "X-Pil: *Gate=https\r\nX-Pil: *Adr=%s\r\n"; 165 } 166 for (n = 1; n < cnt; ++n) 167 ports[n] = atoi(av[n+3]); 168 169 signal(SIGCHLD,SIG_IGN); /* Prevent zombies */ 170 if ((n = fork()) < 0) 171 giveup("detach"); 172 if (n) 173 return 0; 174 setsid(); 175 176 for (;;) { 177 socklen_t len = sizeof(addr); 178 if ((cli = accept(sd, (struct sockaddr*)&addr, &len)) >= 0 && (n = fork()) >= 0) { 179 if (!n) { 180 int fd, port, i; 181 char *p, *q, buf[4096], buf2[64]; 182 183 close(sd); 184 185 alarm(420); 186 if (ssl) { 187 SSL_set_fd(ssl, cli); 188 if (SSL_accept(ssl) < 0) 189 return 1; 190 } 191 n = rdLine(ssl, cli, buf, sizeof(buf)); 192 alarm(0); 193 if (n < 6) 194 return 1; 195 196 /* "GET /url HTTP/1.x" 197 * "GET /8080/url HTTP/1.x" 198 * "POST /url HTTP/1.x" 199 * "POST /8080/url HTTP/1.x" 200 */ 201 if (pre(buf, "GET /")) 202 p = buf + 5; 203 else if (pre(buf, "POST /")) 204 p = buf + 6; 205 else 206 return 1; 207 208 port = (int)strtol(p, &q, 10); 209 if (q == p || *q != ' ' && *q != '/') 210 port = ports[0], q = p; 211 else if (port < cnt) { 212 if ((port = ports[port]) < 0) 213 return 1; 214 } 215 else if (port < 1024) 216 return 1; 217 else 218 for (i = 1; i < cnt; ++i) 219 if (port == -ports[i]) 220 return 1; 221 222 if ((srv = gateConnect((unsigned short)port)) < 0) { 223 if (!memchr(q,'~', buf + n - q)) 224 return 1; 225 if ((fd = open("void", O_RDONLY)) < 0) 226 return 1; 227 alarm(420); 228 if (ssl) 229 sslWrite(ssl, Head_410, strlen(Head_410)); 230 else 231 wrBytes(cli, Head_410, strlen(Head_410)); 232 alarm(0); 233 while ((n = read(fd, buf, sizeof(buf))) > 0) { 234 alarm(420); 235 if (ssl) 236 sslWrite(ssl, buf, n); 237 else 238 wrBytes(cli, buf, n); 239 alarm(0); 240 } 241 return 0; 242 } 243 244 Http1 = 0; 245 wrBytes(srv, buf, p - buf); 246 if (*q == '/') 247 ++q; 248 p = q; 249 while (*p++ != '\n') 250 if (p >= buf + n) 251 return 1; 252 wrBytes(srv, q, p - q); 253 if (pre(p-10, "HTTP/1.")) 254 Http1 = *(p-3) - '0'; 255 inet_ntop(AF_INET6, &addr.sin6_addr, s, INET6_ADDRSTRLEN); 256 wrBytes(srv, buf2, sprintf(buf2, gate, s)); 257 wrBytes(srv, p, buf + n - p); 258 259 signal(SIGALRM, doSigAlarm); 260 signal(SIGUSR1, doSigUsr1); 261 if (Buddy = fork()) { 262 for (;;) { 263 alarm(420); 264 n = slow(ssl, cli, buf, sizeof(buf)); 265 alarm(0); 266 if (!n) 267 break; 268 wrBytes(srv, buf, n); 269 } 270 shutdown(cli, SHUT_RD); 271 shutdown(srv, SHUT_WR); 272 } 273 else { 274 Buddy = getppid(); 275 while ((n = read(srv, buf, sizeof(buf))) > 0) { 276 kill(Buddy, SIGUSR1); 277 alarm(420); 278 if (ssl) 279 sslWrite(ssl, buf, n); 280 else 281 wrBytes(cli, buf, n); 282 alarm(0); 283 } 284 shutdown(srv, SHUT_RD); 285 shutdown(cli, SHUT_WR); 286 } 287 return 0; 288 } 289 close(cli); 290 } 291 } 292 }