diff --git a/Makefile b/Makefile index ab0d675..d17eb01 100644 --- a/Makefile +++ b/Makefile @@ -6,16 +6,23 @@ OBJ = $(BIN:=.o) # OpenBSD: use pledge(2). #CFLAGS += -DUSE_PLEDGE # build static: useful in www chroot. -LDFLAGS += -static +LDFLAGS += -static -lz # Linux #CPPFLAGS += -D_DEFAULT_SOURCE -all: $(BIN) +all: clean config.h $(BIN) $(BIN): $(OBJ) $(CC) $(OBJ) $(LDFLAGS) -o $@ +config.h: + $(CP) config.def.h config.h + $(OBJ): Makefile clean: rm -f $(BIN) $(OBJ) + +install: + cp -f $(BIN) /home/www/cgi-bin/gopherproxy + chmod +x /home/www/cgi-bin/gopherproxy diff --git a/README b/README index 485688d..f9c207f 100644 --- a/README +++ b/README @@ -58,9 +58,12 @@ Notes Tor support: To accept tor gopher browsing, remove the -static flag from LDFLAGS in the -Makefile and modify the isblacklisted() function in gopherproxy.c to allow -.onion addresses. +Makefile set allow_tor to 1 in config.h to allow .onion addresses. +Port restriction: + +For security reasons, only port 70 and 7070 are accepted as valid gopher ports. +If you want allow all ports, set allow_all_ports in config.h Nginx buffering issues: diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..412d467 --- /dev/null +++ b/config.def.h @@ -0,0 +1,6 @@ +/* gopherproxy config file */ + +static int allow_tor = 0; +static int allow_all_ports = 0; +static int disable_urlbar = 0; +static char hostname[] = ""; diff --git a/gopherproxy.c b/gopherproxy.c index e23c85d..9748179 100644 --- a/gopherproxy.c +++ b/gopherproxy.c @@ -1,3 +1,5 @@ +#define _WITH_DPRINTF + #include #include #include @@ -10,9 +12,11 @@ #include #include #include +#include "config.h" +#include -#define MAX_RESPONSETIMEOUT 10 /* timeout in seconds */ -#define MAX_RESPONSESIZ 4000000 /* max download size in bytes */ +#define MAX_RESPONSETIMEOUT 15 /* timeout in seconds */ +#define MAX_RESPONSESIZ 8589934592 /* max download size in bytes */ #ifndef USE_PLEDGE #define pledge(a,b) 0 @@ -32,26 +36,59 @@ struct visited { char port[8]; }; -int headerset = 0; +int headerset = 0, isdir = 0; void die(int code, const char *fmt, ...) { va_list ap; - if (!headerset) { switch (code) { + case 301: + fputs("Status: 200 OK\r\n", stdout); + break; case 400: fputs("Status: 400 Bad Request\r\n", stdout); break; case 403: fputs("Status: 403 Permission Denied\r\n", stdout); break; + case 418: + fputs("Status: 418 I'm a Teapot\r\n", stdout); + break; + case 404: + fputs("Status: 404 Page not found\r\n", stdout); + break; default: fputs("Status: 500 Internal Server Error\r\n", stdout); break; } + + if(code == 301) { + + /* SOURCE */ + Bytef *source; + uLong source_size = 1024*1024*60; + source = malloc(source_size); + memset(source,0, source_size); + + /* SET BOUNDARY */ + uLong dest_size = compressBound(source_size); + Bytef *dest; + dest = malloc(dest_size); + + /* COMPRESS */ + compress(dest, &dest_size, source, source_size); + + /* PRINT HEADER */ + fputs("Content-Encoding: gzip\r\n", stdout); fputs("Content-Type: text/plain; charset=utf-8\r\n\r\n", stdout); + fputs(dest, stdout); + free(source); + free(dest); + } else { + fputs("Content-Type: text/plain; charset=utf-8\r\n\r\n", stdout); + } } va_start(ap, fmt); @@ -62,6 +99,9 @@ die(int code, const char *fmt, ...) vfprintf(stdout, fmt, ap); va_end(ap); + if (isdir) + fputs("\n\n\n", stdout); + exit(1); } @@ -134,9 +174,16 @@ isblacklisted(const char *host, const char *port, const char *path) { char *p; - if (strcmp(port, "70") && strcmp(port, "7070")) +// if(strstr(host, "gopher.viste.fr")) +// return 2; +// if(strstr(host, "taz.de")) +// return 1; +// if(strstr(host, "gopher.661.org")) +// return 1; + + if (!allow_all_ports && (strcmp(port, "70") && strcmp(port, "7070"))) return 1; - if ((p = strstr(host, ".onion")) && strlen(p) == strlen(".onion")) + if (!allow_tor && ((p = strstr(host, ".onion")) && strlen(p) == strlen(".onion"))) return 1; return 0; } @@ -152,11 +199,11 @@ typestr(int c) case '4': return " MAC"; case '5': return " DOS"; case '6': return " UUENC"; - case '7': return "SEARCH"; + case '7': return " SEND"; case '8': return "TELNET"; case '9': return " BIN"; case 'g': return " GIF"; - case 'h': return " HTML"; /* non-standard */ + case 'h': return " URI"; /* non-standard */ case 's': return " SND"; /* non-standard */ case '+': return "MIRROR"; case 'I': return " IMG"; @@ -307,8 +354,13 @@ servedir(const char *server, const char *port, const char *path, const char *par } if (!strcmp(v.port, "70")) + if(!strcmp(v.server, hostname)) { + snprintf(uri, sizeof(uri), "/%c%s", + v._type, v.path); + } else { snprintf(uri, sizeof(uri), "%s/%c%s", v.server, v._type, v.path); + } else snprintf(uri, sizeof(uri), "%s:%s/%c%s", v.server, v.port, v._type, v.path); @@ -329,7 +381,7 @@ servedir(const char *server, const char *port, const char *path, const char *par xmlencode(v.username); fputs( "\" name=\"p\" value=\"\" size=\"72\" />" - "
", stdout);
+                "
", stdout);
             break;
         case '8': /* telnet */
         case 'T': /* tn3270 */
@@ -352,7 +404,15 @@ servedir(const char *server, const char *port, const char *path, const char *par
             if (v._type == 'h' && !strncmp(v.path, "URL:", sizeof("URL:") - 1)) {
                 xmlencode(v.path + sizeof("URL:") - 1);
             } else {
+                if(enable_rewrite == 0) {
                     fputs("?q=", stdout);
+                }
+                if(strncmp(uri, "/", sizeof("/") -1)) {
+                    if(enable_rewrite == 1) {
+                        fputs("/gate?q=", stdout);
+                    }
+                    fputs("gopher://", stdout);
+                }
                 xmlencode(uri);
             }
             fputs("\">", stdout);
@@ -519,7 +579,7 @@ main(void)
         if (!parseuri(uri, &u))
             die(400, "Invalid uri: %s\n", uri);
         if (u.host[0] == '\0')
-			die(400, "Invalid hostname\n");
+            strcpy(u.host, hostname);
 
         if (u.path[0] == '\0')
             memcpy(u.path, "/", 2);
@@ -537,8 +597,12 @@ main(void)
             path = "";
         }
                 
-		if (isblacklisted(u.host, u.port, path))
+                int blret = 0;
+                blret = isblacklisted(u.host, u.port, path);
+        if (blret == 1)
             die(403, "%s:%s %s: blacklisted\n", u.host, u.port, path);
+        if (blret == 2)
+            die(301, "");
 
         headerset = 1;
         switch (_type) {
@@ -581,34 +645,37 @@ main(void)
         }
     }
 
-	headerset = 1;
+    headerset = isdir = 1;
     fputs(
         "Content-Type: text/html; charset=utf-8\r\n"
         "\r\n"
         "\n"
-		"\n"
+        "\n"
         "\n"
+        "\n"
+        "\n"
         "\n"
+        "\n"
         "", stdout);
+        fputs("gopher://codevoid.de", stdout);
+    if (strrchr(path, '/')) {
         xmlencode(query);
-	if (query[0])
-		fputs(" - ", stdout);
+    }
     fputs(
-		"Gopher HTTP proxy\n"
-		"\n"
-		"\n"
-		"\n"
-		"\n"
+        "\n"
         "\n"
-		"\n"
-		"
"
+        "\n", stdout);
+
+    if(!disable_urlbar) {
+        fputs("
"
         "  URI: "
         "
" - "
\n", stdout);
+        "\n", stdout);
+    }
+    fputs("
\n", stdout);
 
     if (query[0]) {
         if (_type != '7')