Better way to do stunnel addr

This commit is contained in:
Neale Pickett 2015-02-26 16:04:43 -07:00
parent 86a75813e3
commit 77c3ed33dd
1 changed files with 359 additions and 449 deletions

218
eris.c
View File

@ -50,44 +50,28 @@
#define DUMP_p(v) DUMPf("%s = %p", #v, v)
#define DUMP_buf(v, l) DUMPf("%s = %.*s", #v, (int)(l), v)
/*
* Wait this long (seconds) for a valid HTTP request
*/
/* Wait this long (seconds) for a valid HTTP request */
#define READTIMEOUT 2
/*
* Wait this long (seconds) for a non-file send to complete
*/
/* Wait this long (seconds) for a non-file send to complete */
#define WRITETIMEOUT 10
/*
* Quit if we can't write at least this many bytes per second
*/
/* Quit if we can't write at least this many bytes per second */
#define MIN_WRITE_RATE 2560
/*
* Wait this long for CGI to complete
*/
/* Wait this long for CGI to complete */
#define CGI_TIMEOUT (5*60)
/*
* How long each sendfile call can take
*/
/* How long each sendfile call can take */
#define SENDFILE_TIMEOUT ((int)(SIZE_MAX / MIN_WRITE_RATE))
/*
* Maximum size of a request header (the whole block)
*/
/* Maximum size of a request header (the whole block) */
#define MAXHEADERLEN 8192
/*
* Maximum size of a request line
*/
/* Maximum size of a request line */
#define MAXREQUESTLEN 2048
/*
* Maximum number of header fields
*/
/* Maximum number of header fields */
#define MAXHEADERFIELDS 60
#define BUFFER_SIZE 8192
@ -104,9 +88,7 @@ int portappend = 0;
char *connector = NULL;
/*
* Variables that persist between requests
*/
/* Variables that persist between requests */
int cwd;
int keepalive = 0;
char *remote_addr = NULL;
@ -140,7 +122,8 @@ dolog(int code, off_t len)
sanitize(user_agent);
sanitize(refer);
fprintf(stderr, "%s %d %lu %s %s %s %s\n", remote_addr, code, (unsigned long) len, host, user_agent, refer, path);
fprintf(stderr, "%s %d %lu %s %s %s %s\n",
remote_addr, code, (unsigned long) len, host, user_agent, refer, path);
}
void
@ -171,7 +154,8 @@ badrequest(long code, const char *httpcomment, const char *message)
if (message) {
msglen = (strlen(message) * 2) + 15;
printf("Content-Length: %lu\r\nContent-Type: text/html\r\n\r\n", (unsigned long) msglen);
printf("Content-Length: %lu\r\nContent-Type: text/html\r\n\r\n",
(unsigned long) msglen);
printf("<title>%s</title>%s", message, message);
}
printf("\r\n");
@ -217,20 +201,23 @@ void
get_ucspi_env()
{
char *ucspi = getenv("PROTO");
char *ip = NULL;
char *port = NULL;
if (ucspi) {
char *p;
/*
* Busybox, as usual, has the right idea
*/
/* Busybox, as usual, has the right idea */
if ((p = proto_getenv(ucspi, "REMOTEADDR"))) {
remote_addr = strdup(p);
} else {
ip = proto_getenv(ucspi, "REMOTEIP");
port = proto_getenv(ucspi, "REMOTEPORT");
char *ip = proto_getenv(ucspi, "REMOTEIP");
char *port = proto_getenv(ucspi, "REMOTEPORT");
if (ip) {
char buf[80];
snprintf(buf, sizeof buf, "%s:%s", ip, port);
remote_addr = strdup(buf);
}
}
if ((p = proto_getenv(ucspi, "REMOTEINFO"))) {
@ -238,12 +225,7 @@ get_ucspi_env()
}
}
if (ip) {
char buf[80];
snprintf(buf, sizeof buf, "%s:%s", ip, port);
remote_addr = strdup(buf);
} else {
if (! remote_addr) {
// stunnel
remote_addr = getenv("REMOTE_ADDR");
}
@ -282,7 +264,8 @@ parse_options(int argc, char *argv[])
exit(0);
case 'h':
default:
fprintf(stderr, "Usage: %s [OPTIONS]\n", argv[0]);
fprintf(stderr, "Usage: %s [OPTIONS]\n",
argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "-a Enable authentication\n");
fprintf(stderr, "-c Enable CGI\n");
@ -309,9 +292,8 @@ sigchld(int sig)
static void
sigalarm_cgi(int sig)
{
/*
* send this out regardless of whether we've already sent a header, to maybe help with debugging
*/
/* send this out regardless of whether we've already sent a header,
* to maybe help with debugging */
badrequest(504, "Gateway Timeout", "The CGI is being too slow.");
}
@ -333,9 +315,7 @@ cgi_child(const char *relpath)
env("CONTENT_TYPE", content_type);
}
/*
* Try to change to CGI's directory
*/
/* Try to change to CGI's directory */
{
char *delim = strrchr(relpath, '/');
@ -376,9 +356,7 @@ cgi_parent(int cin, int cout, int passthru)
nfds = cin;
if (content_length) {
/*
* have post data
*/
/* have post data */
FD_SET(cout, &wfds);
if (cout > nfds) {
nfds = cout;
@ -395,54 +373,38 @@ cgi_parent(int cin, int cout, int passthru)
if (FD_ISSET(cin, &rfds)) {
if (passthru) {
/*
* Pass everything through verbatim
*/
/* Pass everything through verbatim */
size_t len;
/*
* Re-use this big buffer
*/
/* Re-use this big buffer */
len = fread(cgiheader, 1, sizeof cgiheader, cinf);
if (0 == len) {
/*
* CGI is done
*/
/* CGI is done */
break;
}
fwrite(cgiheader, 1, len, stdout);
/*
* Naively assume the CGI knows best about sending stuff
*/
/* Naively assume the CGI knows best about sending stuff */
fflush(stdout);
size += len;
} else {
/*
* Interpret header fields
*/
/* Interpret header fields */
size_t readlen = (sizeof cgiheader) - cgiheaderlen;
if (NULL == fgets(cgiheader + cgiheaderlen, readlen, cinf)) {
/*
* EOF or error
*/
/* EOF or error */
badrequest(500, "CGI Error", "CGI output too weird");
}
cgiheaderlen = strlen(cgiheader);
if ('\n' == cgiheader[cgiheaderlen - 1]) {
/*
* We read a whole line
*/
/* We read a whole line */
size_t len;
char *val;
len = extract_header_field(cgiheader, &val, 0);
if (! len) {
/*
* We've read the entire header block
*/
/* We've read the entire header block */
passthru = 1;
eoh();
} else {
@ -533,9 +495,7 @@ serve_cgi(char *relpath)
close(cin[1]);
close(cout[0]);
/*
* Eris is not this smart yet
*/
/* Eris is not this smart yet */
keepalive = 0;
cgi_parent(cin[0], cout[1], 0);
@ -566,21 +526,15 @@ fake_sendfile(int out_fd, int in_fd, off_t * offset, size_t count)
char buf[BUFFER_SIZE];
ssize_t l, m;
/*
* is mmap quicker? does it matter?
*/
/* is mmap quicker? does it matter? */
if (-1 == lseek(in_fd, *offset, SEEK_SET)) {
/*
* We're screwed. The most helpful thing we can do now is die.
*/
/* We're screwed. The most helpful thing we can do now is die. */
fprintf(stderr, "Unable to seek. Dying.\n");
exit(0);
}
l = read(in_fd, buf, min(count, sizeof buf));
if (-1 == l) {
/*
* Also screwed.
*/
/* Also screwed. */
fprintf(stderr, "Unable to read an open file. Dying.\n");
exit(0);
}
@ -589,9 +543,7 @@ fake_sendfile(int out_fd, int in_fd, off_t * offset, size_t count)
while (l) {
m = write(out_fd, buf, l);
if (-1 == m) {
/*
* ALSO screwed.
*/
/* ALSO screwed. */
fprintf(stderr, "Unable to write to client: %m (req %s). Dying.\n", path);
exit(0);
}
@ -733,21 +685,15 @@ find_serve_file(char *relpath)
int fd;
struct stat st;
/*
* Open fspath. If that worked,
*/
/* Open fspath. If that worked, */
if ((fd = open(relpath, O_RDONLY)) > -1) {
fstat(fd, &st);
/*
* If it is a directory,
*/
/* If it is a directory, */
if (S_ISDIR(st.st_mode)) {
char path2[PATH_MAX];
int fd2;
/*
* Redirect if it doesn't end with /
*/
/* Redirect if it doesn't end with / */
if (! endswith(path, "/")) {
header(301, "Redirect");
printf("Location: %s/\r\n", path);
@ -755,14 +701,10 @@ find_serve_file(char *relpath)
return;
}
/*
* Open relpath + "index.html". If that worked,
*/
/* Open relpath + "index.html". If that worked,*/
snprintf(path2, sizeof path2, "%sindex.html", relpath);
if ((fd2 = open(path2, O_RDONLY)) > -1) {
/*
* serve that file and return.
*/
/* serve that file and return. */
fstat(fd2, &st);
serve_file(fd2, path2, &st);
close(fd2);
@ -815,9 +757,7 @@ handle_request()
char buf[MAXHEADERLEN];
char *p;
/*
* Initialize globals
*/
/* Initialize globals */
host = NULL;
user_agent = NULL;
refer = NULL;
@ -830,14 +770,10 @@ handle_request()
alarm(READTIMEOUT);
/*
* Read request line first
*/
/* Read request line first */
request[0] = 0;
if (NULL == fgets(request, sizeof request, stdin)) {
/*
* They must have hung up!
*/
/* They must have hung up! */
exit(0);
}
if (!strncmp(request, "GET /", 5)) {
@ -853,9 +789,7 @@ handle_request()
method = CONNECT;
p = request + 8;
} else {
/*
* This also handles the case where fgets does nothing
*/
/* This also handles the case where fgets does nothing */
badrequest(405, "Method Not Allowed", "Unsupported HTTP method.");
}
@ -864,9 +798,7 @@ handle_request()
env("REQUEST_METHOD", request);
}
/*
* Interpret path into fspath.
*/
/* Interpret path into fspath. */
path = p;
{
char *fsp = fspath;
@ -903,9 +835,7 @@ handle_request()
}
*fsp = 0;
/*
* Change "/." to "/:" to keep "hidden" files such and prevent directory traversal
*/
/* Change "/." to "/:" to keep "hidden" files such and prevent directory traversal */
while ((fsp = strstr(fspath, "/."))) {
*(fsp+1) = ':';
}
@ -936,9 +866,7 @@ handle_request()
env("SERVER_PROTOCOL", p);
}
/*
* Read header fields
*/
/* Read header fields */
{
char *base = buf;
char *lastchar = base + (sizeof buf) - 2;
@ -952,9 +880,7 @@ handle_request()
char *name, *val;
size_t len;
/*
* 40 is totally arbitrary here.
*/
/* 40 is totally arbitrary here. */
if (plen < 40) {
badrequest(431, "Request Header Too Large", "The HTTP header block was too large");
}
@ -974,9 +900,7 @@ handle_request()
len = extract_header_field(p, &val, 1);
if (! len) {
/*
* blank line
*/
/* blank line */
break;
}
if (! val) {
@ -985,21 +909,15 @@ handle_request()
name = p;
/*
* Set up CGI environment variables
*/
/* Set up CGI environment variables */
if (docgi) {
env(cgi_name, val);
}
/*
* By default, re-use buffer space
*/
/* By default, re-use buffer space */
base = cgi_name;
/*
* Handle special header fields
*/
/* Handle special header fields */
if (! strcmp(name, "HOST")) {
host = val;
base = name + len + 1;
@ -1023,12 +941,8 @@ handle_request()
} else if (! strcmp(name, "IF_MODIFIED_SINCE")) {
ims = timerfc(val);
} else if (! strcmp(name, "RANGE")) {
/*
* Range: bytes=17-23
*/
/*
* Range: bytes=23-
*/
/* Range: bytes=17-23 */
/* Range: bytes=23- */
if (! strncmp(val, "bytes=", 6)) {
p = val + 6;
range_start = (off_t) strtoull(p, &p, 10);
@ -1042,9 +956,7 @@ handle_request()
}
}
/*
* Try to change into the appropriate directory
*/
/* Try to change into the appropriate directory */
if (! nochdir) {
char fn[PATH_MAX];
@ -1080,9 +992,7 @@ handle_request()
badrequest(500, "Unable to exec connector", strerror(errno));
}
/*
* Serve the file
*/
/* Serve the file */
alarm(WRITETIMEOUT);
find_serve_file(fspath);
fflush(stdout);