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);
       +}