Bring the VPN wrapper to a better position

It will not work yet as-is, but this should help getting it there.
This commit is contained in:
Pierre Pronchery 2020-11-15 21:47:14 +01:00
parent 85f264e97a
commit 1586c8314f

View File

@ -16,8 +16,10 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -29,29 +31,62 @@
/* libVPN */ /* libVPN */
/* private */ /* private */
/* types */ /* types */
typedef struct _VPNSocket typedef struct _VPNAppClient
{ {
int fd; String const * name;
} VPNSocket; AppClient * appclient;
} VPNAppClient;
typedef struct _VPNAppClientFD
{
AppClient * appclient;
int32_t fd;
} VPNAppClientFD;
/* constants */ /* constants */
#define APPINTERFACE "VPN"
#define PROGNAME "libVPN" #define PROGNAME "libVPN"
/* variables */ /* 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; static int _vpn_offset = 1024;
/* local functions */ /* local functions */
static int (*old_close)(int fd);
static int (*old_connect)(int fd, const struct sockaddr * name, static int (*old_connect)(int fd, const struct sockaddr * name,
socklen_t namelen); 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 */ /* prototypes */
static void _libvpn_init(void); 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 */ /* functions */
static void _libvpn_init(void) static void _libvpn_init(void)
@ -74,21 +109,29 @@ static void _libvpn_init(void)
fprintf(stderr, "%s: %s\n", PROGNAME, dlerror()); fprintf(stderr, "%s: %s\n", PROGNAME, dlerror());
exit(1); 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()); fprintf(stderr, "%s: %s\n", PROGNAME, dlerror());
dlclose(hdl); dlclose(hdl);
exit(1); exit(1);
} }
dlclose(hdl); dlclose(hdl);
if((_appclient = appclient_new(NULL, "VPN", NULL)) == NULL) #ifdef RLIMIT_NOFILE
if(getrlimit(RLIMIT_NOFILE, &r) == 0)
{ {
error_print(PROGNAME); if(r.rlim_max > INT_MAX)
{
fprintf(stderr, "%s: %s\n", PROGNAME, strerror(ERANGE));
exit(1); exit(1);
} }
#ifdef RLIMIT_NOFILE if(_vpn_offset < r.rlim_max)
if(getrlimit(RLIMIT_NOFILE, &r) == 0 && r.rlim_max > _vpn_offset) _vpn_offset = (int)r.rlim_max;
_vpn_offset = r.rlim_max; }
# ifdef DEBUG # ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %u\n", __func__, _vpn_offset); fprintf(stderr, "DEBUG: %s() %u\n", __func__, _vpn_offset);
# endif # 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 */ /* public */
/* interface */ /* 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 */ /* connect */
int connect(int fd, const struct sockaddr * name, socklen_t namelen) int connect(int fd, const struct sockaddr * name, socklen_t namelen)
{ {
int ret; int ret;
AppClient * appclient;
_libvpn_init(); _libvpn_init();
if(fd < _vpn_offset) if(_libvpn_is_remote(name, namelen) == 0)
return old_connect(fd, name, namelen); return old_connect(fd, name, namelen);
if(appclient_call(_appclient, (void **)&ret, "connect", if((appclient = _libvpn_get_appclient(name, namelen)) == NULL)
fd - _vpn_offset) return -1;
!= 0) if(appclient_call(appclient, (void **)&ret, "connect", fd) != 0)
return -1; return -1;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: connect(%d) => %d\n", fd - VFS_OFFSET, ret); fprintf(stderr, "DEBUG: connect(%d) => %d\n", fd, ret);
#endif #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 _vpn_errno(_vpn_error, _vpn_error_cnt, -ret, 1);
return ret; return ret;
} }