httpGate.c (9022B)
1 /* 14feb08abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <stdarg.h> 8 #include <unistd.h> 9 #include <fcntl.h> 10 #include <errno.h> 11 #include <ctype.h> 12 #include <string.h> 13 #include <signal.h> 14 #include <netdb.h> 15 #include <time.h> 16 #include <sys/time.h> 17 #include <sys/stat.h> 18 #include <sys/socket.h> 19 #include <arpa/inet.h> 20 #include <netinet/tcp.h> 21 #include <netinet/in.h> 22 #include <syslog.h> 23 24 #include <openssl/pem.h> 25 #include <openssl/ssl.h> 26 #include <openssl/err.h> 27 28 typedef enum {NO,YES} bool; 29 30 static bool Bin; 31 static int Http1, Timeout; 32 33 static char Head_200[] = 34 "HTTP/1.0 200 OK\r\n" 35 "Server: PicoLisp\r\n" 36 "Content-Type: text/html; charset=utf-8\r\n" 37 "\r\n"; 38 39 static void logger(char *fmt, ...) { 40 va_list ap; 41 42 va_start(ap,fmt); 43 vsyslog(LOG_ERR, fmt, ap); 44 va_end(ap); 45 } 46 47 static void giveup(char *msg) { 48 fprintf(stderr, "httpGate: %s\n", msg); 49 exit(2); 50 } 51 52 static inline bool pre(char *p, char *s) { 53 while (*s) 54 if (*p++ != *s++) 55 return NO; 56 return YES; 57 } 58 59 static char *ses(char *buf, int port, int *len) { 60 int np; 61 char *p, *q; 62 63 if (Bin || Http1 == 0) 64 return buf; 65 if (pre(buf, "GET /")) { 66 np = (int)strtol(buf+5, &q, 10); 67 if (q == buf+5 || *q != '/' || np < 1024 || np > 65535) 68 return buf; 69 p = q++ - 4; 70 do 71 if (*q < '0' || *q > '9') 72 return buf; 73 while (*++q != '~'); 74 if (np == port) { 75 p[0] = 'G', p[1] = 'E', p[2] = 'T', p[3] = ' '; 76 *len -= p - buf; 77 return p; 78 } 79 return NULL; 80 } 81 if (pre(buf, "POST /")) { 82 np = (int)strtol(buf+6, &q, 10); 83 if (q == buf+6 || *q != '/' || np < 1024 || np > 65535) 84 return buf; 85 p = q++ - 5; 86 do 87 if (*q < '0' || *q > '9') 88 return buf; 89 while (*++q != '~'); 90 if (np == port) { 91 p[0] = 'P', p[1] = 'O', p[2] = 'S', p[3] = 'T', p[4] = ' '; 92 *len -= p - buf; 93 return p; 94 } 95 return NULL; 96 } 97 return buf; 98 } 99 100 static int slow(SSL *ssl, int fd, char *p, int cnt) { 101 int n; 102 103 while ((n = ssl? SSL_read(ssl, p, cnt) : read(fd, p, cnt)) < 0) 104 if (errno != EINTR) 105 return 0; 106 return n; 107 } 108 109 static void wrBytes(int fd, char *p, int cnt) { 110 int n; 111 112 do 113 if ((n = write(fd, p, cnt)) >= 0) 114 p += n, cnt -= n; 115 else if (errno != EINTR) { 116 logger("%d wrBytes error", fd); 117 exit(1); 118 } 119 while (cnt); 120 } 121 122 static void sslWrite(SSL *ssl, void *p, int cnt) { 123 if (SSL_write(ssl, p, cnt) <= 0) { 124 logger("SSL_write error"); 125 exit(1); 126 } 127 } 128 129 static int gateSocket(void) { 130 int sd; 131 132 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 133 logger("socket error"); 134 exit(1); 135 } 136 return sd; 137 } 138 139 static int gatePort(int port) { 140 int n, sd; 141 struct sockaddr_in addr; 142 143 memset(&addr, 0, sizeof(addr)); 144 addr.sin_family = AF_INET; 145 addr.sin_addr.s_addr = htonl(INADDR_ANY); 146 addr.sin_port = htons((unsigned short)port); 147 n = 1, setsockopt(sd = gateSocket(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); 148 if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 149 logger("%d bind error", sd); 150 exit(1); 151 } 152 if (listen(sd,5) < 0) { 153 logger("%d listen error", sd); 154 exit(1); 155 } 156 return sd; 157 } 158 159 static int gateConnect(unsigned short port) { 160 int sd; 161 struct sockaddr_in addr; 162 163 memset(&addr, 0, sizeof(addr)); 164 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 165 sd = gateSocket(); 166 addr.sin_family = AF_INET; 167 addr.sin_port = htons(port); 168 return connect(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0? -1 : sd; 169 } 170 171 172 static pid_t Buddy; 173 174 static void doSigAlarm(int n __attribute__((unused))) { 175 logger("Timeout %d", Timeout); 176 kill(Buddy, SIGTERM); 177 exit(0); 178 } 179 180 static void doSigUsr1(int n __attribute__((unused))) { 181 alarm(Timeout); 182 } 183 184 int main(int ac, char *av[]) { 185 int cnt = ac>4? ac-3 : 1, ports[cnt], n, sd, cli, srv; 186 struct sockaddr_in addr; 187 char *gate; 188 SSL_CTX *ctx; 189 SSL *ssl; 190 191 if (ac < 3) 192 giveup("port dflt [pem [alt ..]]"); 193 194 sd = gatePort(atoi(av[1])); // e.g. 80 or 443 195 ports[0] = atoi(av[2]); // e.g. 8080 196 if (ac == 3 || *av[3] == '\0') 197 ssl = NULL, gate = "Gate: http %s\r\n"; 198 else { 199 SSL_library_init(); 200 SSL_load_error_strings(); 201 if (!(ctx = SSL_CTX_new(SSLv23_server_method())) || 202 !SSL_CTX_use_certificate_file(ctx, av[3], SSL_FILETYPE_PEM) || 203 !SSL_CTX_use_PrivateKey_file(ctx, av[3], SSL_FILETYPE_PEM) || 204 !SSL_CTX_check_private_key(ctx) ) { 205 ERR_print_errors_fp(stderr); 206 giveup("SSL init"); 207 } 208 ssl = SSL_new(ctx), gate = "Gate: https %s\r\n"; 209 } 210 for (n = 1; n < cnt; ++n) 211 ports[n] = atoi(av[n+3]); 212 213 signal(SIGCHLD,SIG_IGN); /* Prevent zombies */ 214 if ((n = fork()) < 0) 215 giveup("detach"); 216 if (n) 217 return 0; 218 setsid(); 219 220 openlog("httpGate", LOG_CONS|LOG_PID, 0); 221 for (;;) { 222 socklen_t len = sizeof(addr); 223 if ((cli = accept(sd, (struct sockaddr*)&addr, &len)) >= 0 && (n = fork()) >= 0) { 224 if (!n) { 225 int fd, port; 226 char *p, *q, buf[4096], buf2[64]; 227 228 close(sd); 229 230 alarm(Timeout = 420); 231 if (ssl) { 232 SSL_set_fd(ssl, cli); 233 if (SSL_accept(ssl) < 0) 234 return 1; 235 n = SSL_read(ssl, buf, sizeof(buf)); 236 } 237 else 238 n = read(cli, buf, sizeof(buf)); 239 alarm(0); 240 if (n < 6) 241 return 1; 242 243 /* "@8080 " 244 * "GET /url HTTP/1.x" 245 * "GET /8080/url HTTP/1.x" 246 * "POST /url HTTP/1.x" 247 * "POST /8080/url HTTP/1.x" 248 */ 249 Bin = NO; 250 if (buf[0] == '@') 251 p = buf + 1, Bin = YES, Timeout = 3600; 252 else if (pre(buf, "GET /")) 253 p = buf + 5; 254 else if (pre(buf, "POST /")) 255 p = buf + 6; 256 else 257 return 1; 258 259 port = (int)strtol(p, &q, 10); 260 if (q == p || *q != ' ' && *q != '/') 261 port = ports[0], q = p; 262 else if (port < cnt) 263 port = ports[port]; 264 else if (port < 1024) 265 return 1; 266 267 if ((srv = gateConnect((unsigned short)port)) < 0) { 268 logger("Can't connect to %d", port); 269 if (!memchr(q,'~', buf + n - q)) { 270 buf[n] = '\0'; 271 logger("Bad request: %s", buf); 272 return 1; 273 } 274 if ((fd = open("void", O_RDONLY)) < 0) 275 return 1; 276 alarm(Timeout); 277 if (ssl) 278 sslWrite(ssl, Head_200, strlen(Head_200)); 279 else 280 wrBytes(cli, Head_200, strlen(Head_200)); 281 alarm(0); 282 while ((n = read(fd, buf, sizeof(buf))) > 0) { 283 alarm(Timeout); 284 if (ssl) 285 sslWrite(ssl, buf, n); 286 else 287 wrBytes(cli, buf, n); 288 alarm(0); 289 } 290 return 0; 291 } 292 293 Http1 = 0; 294 if (buf[0] == '@') 295 p = q + 1; 296 else { 297 wrBytes(srv, buf, p - buf); 298 if (*q == '/') 299 ++q; 300 p = q; 301 while (*p++ != '\n') 302 if (p >= buf + n) { 303 buf[n] = '\0'; 304 logger("Bad header: %s", buf); 305 return 1; 306 } 307 wrBytes(srv, q, p - q); 308 if (pre(p-10, "HTTP/1.")) 309 Http1 = *(p-3) - '0'; 310 wrBytes(srv, buf2, sprintf(buf2, gate, inet_ntoa(addr.sin_addr))); 311 } 312 wrBytes(srv, p, buf + n - p); 313 314 signal(SIGALRM, doSigAlarm); 315 signal(SIGUSR1, doSigUsr1); 316 if (Buddy = fork()) { 317 for (;;) { 318 alarm(Timeout); 319 n = slow(ssl, cli, buf, sizeof(buf)); 320 alarm(0); 321 if (!n || !(p = ses(buf, port, &n))) 322 break; 323 wrBytes(srv, p, n); 324 } 325 shutdown(cli, SHUT_RD); 326 shutdown(srv, SHUT_WR); 327 } 328 else { 329 Buddy = getppid(); 330 while ((n = read(srv, buf, sizeof(buf))) > 0) { 331 kill(Buddy, SIGUSR1); 332 alarm(Timeout); 333 if (ssl) 334 sslWrite(ssl, buf, n); 335 else 336 wrBytes(cli, buf, n); 337 alarm(0); 338 } 339 shutdown(srv, SHUT_RD); 340 shutdown(cli, SHUT_WR); 341 } 342 return 0; 343 } 344 close(cli); 345 } 346 } 347 }