From c8d6ce89f19aaa459d5a86c7909d3f3b6aac15d4 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sat, 2 Sep 2023 18:36:29 +0200 Subject: cmd: add socksfs --- src/cmd/socksfs/socksfs.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 src/cmd/socksfs/socksfs.c (limited to 'src/cmd/socksfs') diff --git a/src/cmd/socksfs/socksfs.c b/src/cmd/socksfs/socksfs.c new file mode 100644 index 0000000..4f530f4 --- /dev/null +++ b/src/cmd/socksfs/socksfs.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + hid_t sock; +} Handle; + +static char *socks_addr; + +static void* +fs_open(char *path, int flags) { + char *tokp; + + if (*path++ != '/') { + return errno = ENOENT, NULL; + } + if (!OPEN_WRITEABLE(flags)) { + return errno = EACCES, NULL; + } + + const char *verb = strtok_r(path, "/", &tokp); + if (!verb) { + return errno = ENOENT, NULL; + } + if (strcmp(verb, "connect") != 0) { + return errno = ENOSYS, NULL; // unimpl. + } + + // TODO ip parsing in stdlib + // uint32_t srcip; + //if (ip_parse(strtok_r(NULL, "/", &tokp), &srcip) < 0 || srcip != 0) { + // return errno = ENOENT, NULL; + //} + strtok_r(NULL, "/", &tokp); + + char *dest = strtok_r(NULL, "/", &tokp); + if (!dest) return errno = ENOENT, NULL; + size_t destlen = strlen(dest); + if (destlen >= 256) return errno = ENAMETOOLONG, NULL; + // let's assume it's a domain + + char *proto = strtok_r(NULL, "/", &tokp); + if (!proto) return errno = ENOENT, NULL; + if (strcmp(proto, "tcp") != 0) { + return errno = ENOSYS, NULL; // unimpl. + } + + char *port_s = strtok_r(NULL, "/", &tokp); + if (!port_s) return errno = ENOENT, NULL; + uint16_t port = strtol(port_s, NULL, 0); + + Handle *h; + h = calloc(1, sizeof(*h)); + if (!h) return errno = ENOMEM, NULL; + + h->sock = camellia_open(socks_addr, OPEN_READ | OPEN_WRITE); + if (h->sock < 0) { + goto err; + } + + /* 0x05 version 5 + * 0x01 one authentication method: + * 0x00 no auth */ + char buf[512]; + sleep(1); // TODO fix the netstack + write(h->sock, "\x05\x01\x00", 3); + + errno = EGENERIC; + ssize_t ret = read(h->sock, buf, 2); + if (ret != 2) goto err; // yeah yeah i know + if (memcmp(buf, "\x05\x00", 2) != 0) goto err; + + int p = 0; + buf[p++] = 5; /* v5 */ + buf[p++] = 1; /* tcp connection */ + buf[p++] = 0; /* reserved */ + buf[p++] = 3; /* addr type, 3 = domain */ + buf[p++] = destlen; /* length, max 255 */ + memcpy(buf + p, dest, destlen); + p += destlen; + buf[p++] = port >> 8; + buf[p++] = port; + + write(h->sock, buf, p); + + ret = read(h->sock, buf, 10); + // just comparing to what tor replies, i have bigger issues than making this general + if (ret != 10 || memcmp(buf, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10) != 0) { + goto err; + } + + return h; + +err: + close(h->sock); + free(h); + return NULL; +} + +int main(int argc, char *argv[]) { + const size_t buflen = 4096; + char *buf = malloc(buflen); + + if (argc != 2) { + fprintf(stderr, "usage: socksfs /net/connect/.../\n"); + return 1; + } + socks_addr = argv[1]; + + struct ufs_request req; + hid_t reqh; + // TODO an fs_wait flag to only wait for OPENs, and then to only wait for a given handle + // then i can use proper threads + while ((reqh = ufs_wait(buf, buflen, &req))) { + Handle *h = req.id; + switch (req.op) { + case VFSOP_OPEN: { + void *ret = fs_open(buf, req.flags); + if (ret) { + _sys_fs_respond(reqh, ret, 0, 0); + } else { + _sys_fs_respond(reqh, NULL, -errno, 0); + } + break; + } + case VFSOP_READ: { + if (_sys_fork(FORK_NOREAP, NULL) == 0) { + int len = MIN(buflen, req.capacity); + len = _sys_read(h->sock, buf, len, -1); + _sys_fs_respond(reqh, buf, len, 0); + exit(0); + } else { + close(reqh); + } + break; + } + case VFSOP_WRITE: { + if (_sys_fork(FORK_NOREAP, NULL) == 0) { + int len = _sys_write(h->sock, buf, req.len, -1, 0); + _sys_fs_respond(reqh, NULL, len, 0); + exit(0); + } else { + close(reqh); + } + break; + } + case VFSOP_CLOSE: + close(h->sock); + free(h); + _sys_fs_respond(reqh, NULL, -1, 0); + break; + default: + _sys_fs_respond(reqh, NULL, -1, 0); + break; + } + } +} -- cgit v1.2.3