From 1586c8314f779e1659fbb65e56b1f3a1e8131831 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 15 Nov 2020 21:47:14 +0100 Subject: [PATCH] Bring the VPN wrapper to a better position It will not work yet as-is, but this should help getting it there. --- tools/libvpn.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 336 insertions(+), 18 deletions(-) diff --git a/tools/libvpn.c b/tools/libvpn.c index adebbec..95e50bc 100644 --- a/tools/libvpn.c +++ b/tools/libvpn.c @@ -16,8 +16,10 @@ #include +#include #include #include +#include #include #include #include @@ -29,29 +31,62 @@ /* libVPN */ /* private */ /* types */ -typedef struct _VPNSocket +typedef struct _VPNAppClient { - int fd; -} VPNSocket; + String const * name; + AppClient * appclient; +} VPNAppClient; + +typedef struct _VPNAppClientFD +{ + AppClient * appclient; + int32_t fd; +} VPNAppClientFD; /* constants */ +#define APPINTERFACE "VPN" #define PROGNAME "libVPN" /* variables */ -static AppClient * _appclient = NULL; +static VPNAppClient * _vpn_clients = NULL; +static size_t _vpn_clients_cnt = 0; + +static VPNAppClientFD * _vpn_clients_fd = NULL; +static size_t _vpn_clients_fd_cnt = 0; static int _vpn_offset = 1024; /* local functions */ +static int (*old_close)(int fd); static int (*old_connect)(int fd, const struct sockaddr * name, socklen_t namelen); +static ssize_t (*old_read)(int fd, void * buf, size_t count); +static ssize_t (*old_recv)(int fd, void * buf, size_t count, int flags); +static ssize_t (*old_send)(int fd, void const * buf, size_t count, int flags); +static ssize_t (*old_write)(int fd, void const * buf, size_t count); /* prototypes */ static void _libvpn_init(void); +/* accessors */ +static AppClient * _libvpn_get_appclient(const struct sockaddr * name, + socklen_t namelen); +static AppClient * _libvpn_get_appclient_fd(int32_t * fd); +static String * _libvpn_get_remote_host( + const struct sockaddr * name, socklen_t namelen); +static int _libvpn_get_remote_name( + const struct sockaddr * name, socklen_t namelen, + struct sockaddr ** rname, socklen_t * rnamelen); +static unsigned int _libvpn_is_remote(const struct sockaddr * name, + socklen_t namelen); + +/* useful */ +static int _libvpn_deregister_fd(AppClient * appclient, int32_t fd); +static int _libvpn_register_fd(AppClient * appclient, int32_t * fd); + /* functions */ static void _libvpn_init(void) @@ -74,21 +109,29 @@ static void _libvpn_init(void) fprintf(stderr, "%s: %s\n", PROGNAME, dlerror()); exit(1); } - if((old_connect = dlsym(hdl, "connect")) == NULL) + if((old_close = dlsym(hdl, "close")) == NULL + || (old_connect = dlsym(hdl, "connect")) == NULL + || (old_read = dlsym(hdl, "read")) == NULL + || (old_recv = dlsym(hdl, "recv")) == NULL + || (old_send = dlsym(hdl, "send")) == NULL + || (old_write = dlsym(hdl, "write")) == NULL) { fprintf(stderr, "%s: %s\n", PROGNAME, dlerror()); dlclose(hdl); exit(1); } dlclose(hdl); - if((_appclient = appclient_new(NULL, "VPN", NULL)) == NULL) - { - error_print(PROGNAME); - exit(1); - } #ifdef RLIMIT_NOFILE - if(getrlimit(RLIMIT_NOFILE, &r) == 0 && r.rlim_max > _vpn_offset) - _vpn_offset = r.rlim_max; + if(getrlimit(RLIMIT_NOFILE, &r) == 0) + { + if(r.rlim_max > INT_MAX) + { + fprintf(stderr, "%s: %s\n", PROGNAME, strerror(ERANGE)); + exit(1); + } + if(_vpn_offset < r.rlim_max) + _vpn_offset = (int)r.rlim_max; + } # ifdef DEBUG fprintf(stderr, "DEBUG: %s() %u\n", __func__, _vpn_offset); # endif @@ -96,24 +139,299 @@ static void _libvpn_init(void) } +/* accessors */ +/* libvpn_get_appclient */ +static AppClient * _libvpn_get_appclient(const struct sockaddr * name, + socklen_t namelen) +{ + String * host; + size_t i; + VPNAppClient * p; + + if((host = _libvpn_get_remote_host(name, namelen)) == NULL) + return NULL; + for(i = 0; i < _vpn_clients_cnt; i++) + if(_vpn_clients[i].name == NULL) + continue; + else if(string_compare(_vpn_clients[i].name, host) == 0) + { + string_delete(host); + return _vpn_clients[i].appclient; + } + if((p = realloc(_vpn_clients, sizeof(*_vpn_clients) * (i + 1))) == NULL) + { + string_delete(host); + return NULL; + } + _vpn_clients = p; + p = &_vpn_clients[_vpn_clients_cnt++]; + if((p->appclient = appclient_new(NULL, APPINTERFACE, host)) == NULL) + { + string_delete(host); + return NULL; + } + p->name = host; + return p->appclient; +} + + +/* libvpn_get_appclient_fd */ +static AppClient * _libvpn_get_appclient_fd(int32_t * fd) +{ + size_t i; + + if(*fd < _vpn_offset) + return NULL; + i = (size_t)*fd - _vpn_offset; + if(i >= _vpn_clients_fd_cnt) + return NULL; + *fd = _vpn_clients_fd[i].fd; + return _vpn_clients_fd[i].appclient; +} + + +/* libvpn_get_remote_host */ +static String * _libvpn_get_remote_host( + const struct sockaddr * name, socklen_t namelen) +{ + (void) name; + (void) namelen; + + /* FIXME really implement through gethostbyname()/getaddrinfo() */ + return getenv("APPSERVER_VPN"); +} + + +/* libvpn_get_remote_name */ +static int _libvpn_get_remote_name( + const struct sockaddr * name, socklen_t namelen, + struct sockaddr ** rname, socklen_t * rnamelen) +{ + /* FIXME really implement through gethostbyname()/getaddrinfo() */ + if(rname == NULL && rnamelen == NULL) + return 0; + return -1; +} + + +/* libvpn_is_remote */ +static unsigned int _libvpn_is_remote(const struct sockaddr * name, + socklen_t namelen) +{ + return (_libvpn_get_remote_name(name, namelen, NULL, NULL) == 0) + ? 1 : 0; +} + + +/* useful */ +/* libvpn_deregister_fd */ +static int _libvpn_deregister_fd(AppClient * appclient, int32_t fd) +{ + if(fd < 0 || (size_t)fd >= _vpn_clients_fd_cnt) + return -1; + /* sanity check */ + if(_vpn_clients_fd[fd].appclient != appclient) + return -1; + _vpn_clients_fd[fd].appclient = NULL; + _vpn_clients_fd[fd].fd = -1; + return 0; +} + + +/* libvpn_register_fd */ +static int _libvpn_register_fd(AppClient * appclient, int32_t * fd) +{ + size_t i; + VPNAppClientFD * p; + + for(i = 0; i < _vpn_clients_fd_cnt; i++) + if(_vpn_clients_fd[i].fd < 0) + { + _vpn_clients_fd[i].appclient = appclient; + _vpn_clients_fd[i].fd = *fd; + *fd = _vpn_offset + i; + return 0; + } + if((p = realloc(_vpn_clients_fd, sizeof(*p) * (i + 1))) == NULL) + return -1; + _vpn_clients_fd = p; + p = &_vpn_clients_fd[_vpn_clients_fd_cnt++]; + p->appclient = appclient; + p->fd = *fd; + *fd = _vpn_offset + i; + return 0; +} + + /* public */ /* interface */ +/* close */ +int close(int fd) +{ + int ret; + AppClient * appclient; + + _libvpn_init(); + if((appclient = _libvpn_get_appclient_fd(&fd)) == NULL) + return old_close(fd); + if(appclient_call(appclient, (void **)&ret, "close", fd) != 0) + return -1; +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p:%d) => %d\n", __func__, + (void *)appclient, fd, ret); +#endif + if(ret != 0) + return _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1); + else + _libvpn_deregister_fd(appclient, fd); + return ret; +} + + /* connect */ int connect(int fd, const struct sockaddr * name, socklen_t namelen) { int ret; + AppClient * appclient; _libvpn_init(); - if(fd < _vpn_offset) + if(_libvpn_is_remote(name, namelen) == 0) return old_connect(fd, name, namelen); - if(appclient_call(_appclient, (void **)&ret, "connect", - fd - _vpn_offset) - != 0) + if((appclient = _libvpn_get_appclient(name, namelen)) == NULL) + return -1; + if(appclient_call(appclient, (void **)&ret, "connect", fd) != 0) return -1; #ifdef DEBUG - fprintf(stderr, "DEBUG: connect(%d) => %d\n", fd - VFS_OFFSET, ret); + fprintf(stderr, "DEBUG: connect(%d) => %d\n", fd, ret); #endif - if(ret != 0) + if(ret < 0) + return _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1); + if(_libvpn_register_fd(appclient, &ret) != 0) + { + appclient_call(appclient, NULL, "close", ret); + return -1; + } + return ret; +} + + +/* read */ +ssize_t read(int fd, void * buf, size_t count) +{ + int32_t ret; + AppClient * appclient; + Buffer * b; + + _libvpn_init(); + if((appclient = _libvpn_get_appclient_fd(&fd)) == NULL) + return old_read(fd, buf, count); + if((b = buffer_new(0, NULL)) == NULL) + return -1; + if(appclient_call(appclient, (void **)&ret, "recv", fd, b, count, + 0) != 0) + { + buffer_delete(b); + /* FIXME define errno */ + return -1; + } +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p:%d, buf, %lu) => %d\n", __func__, + (void *)appclient, fd, count, ret); +#endif + if(ret < 0) + ret = _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1); + else if(ret > 0) + memcpy(buf, buffer_get_data(b), ret); + buffer_delete(b); + return ret; +} + + +/* recv */ +ssize_t recv(int fd, void * buf, size_t count, int flags) +{ + int32_t ret; + AppClient * appclient; + Buffer * b; + + _libvpn_init(); + if((appclient = _libvpn_get_appclient_fd(&fd)) == NULL) + return old_read(fd, buf, count); + if((b = buffer_new(0, NULL)) == NULL) + return -1; + if(appclient_call(appclient, (void **)&ret, "recv", fd, b, count, + flags) != 0) + { + buffer_delete(b); + /* FIXME define errno */ + return -1; + } +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p:%d, buf, %lu, %#x) => %d\n", __func__, + (void *)appclient, fd, count, flags, ret); +#endif + if(ret < 0) + ret = _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1); + else if(ret > 0) + memcpy(buf, buffer_get_data(b), ret); + buffer_delete(b); + return ret; +} + + +/* send */ +ssize_t send(int fd, void const * buf, size_t count, int flags) +{ + int32_t ret; + AppClient * appclient; + Buffer * b; + + _libvpn_init(); + if((appclient = _libvpn_get_appclient_fd(&fd)) == NULL) + return old_write(fd, buf, count); + if((b = buffer_new(count, buf)) == NULL) + return -1; + if(appclient_call(appclient, (void **)&ret, "send", fd, b, count, + flags) != 0) + { + buffer_delete(b); + return -1; + } +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%d, buf, %lu, %#x) => %d\n", __func__, + fd, count, flags, ret); +#endif + buffer_delete(b); + if(ret < 0) + return _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1); + return ret; +} + + +/* write */ +ssize_t write(int fd, void const * buf, size_t count) +{ + int32_t ret; + AppClient * appclient; + Buffer * b; + + _libvpn_init(); + if((appclient = _libvpn_get_appclient_fd(&fd)) == NULL) + return old_write(fd, buf, count); + if((b = buffer_new(count, buf)) == NULL) + return -1; + if(appclient_call(appclient, (void **)&ret, "send", fd, b, count, + 0) != 0) + { + buffer_delete(b); + return -1; + } +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%d, buf, %lu) => %d\n", __func__, + fd, count, ret); +#endif + buffer_delete(b); + if(ret < 0) return _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1); return ret; }