tInitial commit - phroxy - Gopher to HTTP proxy
(HTM) git clone git://git.z3bra.org/phroxy.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
(DIR) commit c3904deacd7faa41c91e97ae247e0791c945138f
(HTM) Author: Willy Goiffon <dev@z3bra.org>
Date: Fri, 11 Sep 2020 21:56:03 +0200
Initial commit
Based off sacc and bitreich-httpd from bitreich.org. Thank you :)
Diffstat:
A LICENSE | 13 +++++++++++++
A config.mk | 9 +++++++++
A makefile | 19 +++++++++++++++++++
A mkfile | 22 ++++++++++++++++++++++
A phroxy.c | 309 +++++++++++++++++++++++++++++++
5 files changed, 372 insertions(+), 0 deletions(-)
---
(DIR) diff --git a/LICENSE b/LICENSE
t@@ -0,0 +1,13 @@
+Copyright (c) 2020 Willy Goiffon <dev@z3bra.org>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
(DIR) diff --git a/config.mk b/config.mk
t@@ -0,0 +1,9 @@
+CC = cc
+LD = ${CC}
+
+PREFIX = /usr/local
+MANDIR = ${PREFIX}/man
+
+CPPFLAGS =
+CFLAGS = -Wall -Wextra
+LDFLAGS =
(DIR) diff --git a/makefile b/makefile
t@@ -0,0 +1,19 @@
+include config.mk
+
+all: phroxy
+
+phroxy: phroxy.o
+ ${LD} ${LDFLAGS} -o $@ phroxy.o
+
+install: phroxy phroxy.8
+ mkdir -p ${DESTDIR}${PREFIX}/bin
+ mkdir -p ${DESTDIR}${MANDIR}/man1
+ cp phroxy ${DESTDIR}${PREFIX}/bin/phroxy
+ cp phroxy.8 ${DESTDIR}${MANDIR}/man8/phroxy.8
+
+uninstall:
+ rm ${DESTDIR}${PREFIX}/bin/phroxy
+ rm ${DESTDIR}${MANDIR}/man1/phroxy.8
+
+clean:
+ rm -f phroxy *.o
(DIR) diff --git a/mkfile b/mkfile
t@@ -0,0 +1,22 @@
+<config.mk
+
+all:V: phroxy
+
+phroxy: phroxy.o
+ $LD $LDFLAGS -o $target $prereq
+
+%.o: %.c
+ $CC $CPPFLAGS $CFLAGS -c $stem.c
+
+install:V: phroxy phroxy.8
+ mkdir -p ${DESTDIR}${PREFIX}/bin
+ mkdir -p ${DESTDIR}${MANDIR}/man1
+ cp phroxy ${DESTDIR}${PREFIX}/bin/phroxy
+ cp phroxy.8 ${DESTDIR}${MANDIR}/man8/phroxy.8
+
+uninstall:V:
+ rm ${DESTDIR}${PREFIX}/bin/phroxy
+ rm ${DESTDIR}${MANDIR}/man1/phroxy.8
+
+clean:V:
+ rm -f phroxy *.o
(DIR) diff --git a/phroxy.c b/phroxy.c
t@@ -0,0 +1,309 @@
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/socket.h>
+
+const char *host = "z3bra.org";
+
+void *
+xreallocarray(void *m, const size_t n, const size_t s)
+{
+ void *nm;
+
+ if (n == 0 || s == 0) {
+ free(m);
+ return NULL;
+ }
+ if (s && n > (size_t)-1/s)
+ errx(1, "realloc: overflow");
+ if (!(nm = realloc(m, n * s)))
+ errx(1, "realloc: %s", strerror(errno));
+
+ return nm;
+}
+
+
+static int
+connectto(const char *host, const char *port)
+{
+ sigset_t set, oset;
+ static const struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ };
+ struct addrinfo *addrs, *addr;
+ int r, sock = -1;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGWINCH);
+ sigprocmask(SIG_BLOCK, &set, &oset);
+
+ if ((r = getaddrinfo(host, port, &hints, &addrs))) {
+ fprintf(stderr, "Can't resolve hostname \"%s\": %s", host, gai_strerror(r));
+ goto err;
+ }
+
+ for (addr = addrs; addr; addr = addr->ai_next) {
+ if ((sock = socket(addr->ai_family, addr->ai_socktype,
+ addr->ai_protocol)) < 0)
+ continue;
+ if ((r = connect(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
+ close(sock);
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo(addrs);
+
+ if (sock < 0) {
+ fprintf(stderr, "Can't open socket: %s", strerror(errno));
+ goto err;
+ }
+ if (r < 0) {
+ fprintf(stderr, "Can't connect to: %s:%s: %s", host, port, strerror(errno));
+ goto err;
+ }
+
+ sigprocmask(SIG_SETMASK, &oset, NULL);
+ return sock;
+
+err:
+ sigprocmask(SIG_SETMASK, &oset, NULL);
+ return -1;
+}
+
+int
+sendselector(int sock, const char *selector)
+{
+ char *msg, *p;
+ size_t ln;
+ ssize_t n;
+
+ ln = strlen(selector) + 3;
+ msg = p = malloc(ln);
+ snprintf(msg, ln--, "%s\r\n", selector);
+
+ while ((n = write(sock, p, ln)) > 0) {
+ ln -= n;
+ p += n;
+ }
+
+ free(msg);
+ if (n == -1)
+ fprintf(stderr, "Can't send message: %s", strerror(errno));
+
+ return n;
+}
+
+char *
+getrawitem(int sock, size_t *sz)
+{
+ char *raw, *buf;
+ size_t bn, bs;
+ ssize_t n;
+
+ raw = buf = NULL;
+ bn = bs = n = 0;
+
+ do {
+ bs -= n;
+ buf += n;
+ if (bs < 1) {
+ raw = xreallocarray(raw, ++bn, BUFSIZ);
+ buf = raw + (bn-1) * BUFSIZ;
+ bs = BUFSIZ;
+ }
+ } while ((n = read(sock, buf, bs)) > 0);
+
+ *buf = '\0';
+
+ if (sz)
+ *sz = buf - raw;
+
+ if (n < 0) {
+ fprintf(stderr, "Can't read socket: %s", strerror(errno));
+ free(raw);
+ }
+
+ return raw;
+}
+
+void
+print400(void)
+{
+ printf("HTTP/1.1 400 That's Illegal\r\n");
+ printf("\r\n");
+}
+
+void
+print404(void)
+{
+ printf("HTTP/1.1 404 Google Broke The Web\r\n");
+ printf("\r\n");
+}
+
+void
+print405(void)
+{
+ printf("HTTP/1.1 405 Don't Do That\r\n");
+ printf("\r\n");
+}
+
+void
+print415(void)
+{
+ printf("HTTP/1.1 415 Gopher Type Not Handled\r\n");
+ printf("\r\n");
+}
+
+void
+print500(void)
+{
+ printf("HTTP/1.1 500 You Broke The Web\r\n");
+ printf("\r\n");
+}
+
+char *
+contenttype(char i)
+{
+ switch(i) {
+ case '0':
+ case '1':
+ return "text/plain; charset=utf-8";
+ break; /* NOTREACHED */
+ case '9':
+ return "application/octet-stream";
+ break; /* NOTREACHED */
+ }
+
+ return NULL;
+}
+
+void
+printheaders(char *ctype)
+{
+ time_t t;
+
+ t = time(NULL);
+ if (t > 0)
+ printf("Date: %s", asctime(gmtime(&t)));
+ if (ctype)
+ printf("Content-Type: %s\r\n", ctype);
+ printf("Server: phroxy\r\n");
+ printf("Host: %s\r\n", host);
+ printf("Connection: close\r\n");
+}
+
+
+int
+serveitem(char item, char *data, size_t len)
+{
+ char *sendi;
+ int sent;
+
+ switch(item) {
+ case '0':
+ case '1':
+ case '6':
+ case '9':
+ case 'g':
+ case 'I':
+ break;
+
+ case '2': // Item is a CSO phone-book server
+ case '3': // Error
+ case '4': // Item is a BinHexed Macintosh file.
+ case '5': // Item is DOS binary archive of some sort.
+ case '7': // Item is an Index-Search server.
+ case '8': // Item points to a text-based telnet session.
+ case 'T': // Item points to a text-based tn3270 session.
+ case '+':
+ default:
+ /* IGNORE */
+ print415();
+ break;
+ }
+
+ printf("HTTP/1.1 200 OK\r\n");
+ printheaders(contenttype(item));
+
+
+ printf("Content-Length: %ld\r\n", len);
+ printf("\r\n");
+ fflush(stdout);
+
+ sendi = data;
+ while (len > 0) {
+ if ((sent = write(1, sendi, len)) < 0)
+ return 1;
+ len -= sent;
+ sendi += sent;
+ }
+
+ return 0;
+}
+
+int
+phroxy(char *url)
+{
+ int sock;
+ size_t len;
+ char item, *hole, *path, *host, *port;
+ char *data;
+
+ hole = url + 1;
+ hole = strsep(&hole, "/");
+ item = hole[strlen(hole) + 1];
+ path = hole + strlen(hole) + 2;
+
+ host = strtok(hole, ":");
+ port = strtok(NULL, "\0");
+ if (!port)
+ port = "70";
+
+ sock = connectto(host, port);
+ if (!sendselector(sock, path))
+ data = getrawitem(sock, &len);
+
+ close(sock);
+
+ if (!data)
+ return 1;
+
+ serveitem(item, data, len);
+
+ return 0;
+}
+
+int
+main(void)
+{
+ ssize_t rlen;
+ char request[512], *url;
+
+ rlen = read(0, request, sizeof(request) - 1);
+ if (rlen < 0)
+ return 1;
+
+ request[rlen] = '\0';
+
+ if (strncmp(request, "GET ", 4)) {
+ print405();
+ return 1;
+ }
+
+ url = strtok(request + 4, " ");
+
+ return phroxy(url);
+}