phroxy

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.z3bra.org/phroxy.git
Log | Files | Refs | LICENSE

commit c3904deacd7faa41c91e97ae247e0791c945138f
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:
ALICENSE | 13+++++++++++++
Aconfig.mk | 9+++++++++
Amakefile | 19+++++++++++++++++++
Amkfile | 22++++++++++++++++++++++
Aphroxy.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 372 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -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. diff --git a/config.mk b/config.mk @@ -0,0 +1,9 @@ +CC = cc +LD = ${CC} + +PREFIX = /usr/local +MANDIR = ${PREFIX}/man + +CPPFLAGS = +CFLAGS = -Wall -Wextra +LDFLAGS = diff --git a/makefile b/makefile @@ -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 diff --git a/mkfile b/mkfile @@ -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 diff --git a/phroxy.c b/phroxy.c @@ -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); +}