/* sordid hack to get VLM to run without special privilege.
*
* Inhibit certain calls which require net capabilities or root,
* but lie, and say they succeeded.
*
* Note fd returned by opening /dev/net/tun, with the intent to
* override the tun0 (sic) tap requested by VLM with the tap
* device specified in the VLM_TAP environment variable.
*
* Use LD_PRELOAD to load this ahead of the VLM binary.
*
* N.B. VLM doesn't like xlib-xcb based libX11.so. You need
* an older variant such as the one in Slackware 10.2. Use
* LD_LIBRARY_PATH so this shadows the normal library.
*
* Also, if you run NFS different machine than on your host, you
* need to tell Genera the IP of the NFS host prior to invoking
* Define Site.
*
* Say you've set up the NFS on a Linux VM with a tap configured
* as 10.0.0.1, and your VLM is at 10.0.0.2. Assuming you've
* properly configured your .VLM file, on booting Genera, you need
* to tell the listener:
*
* (setf (cadar (send net:*emb-host* :address)) "10.0.0.1")
*
* Now you may Define Site/Reset Network/Save World.
*
* Happy hacking!
*
* `(john q ,(gensym)) - July 16, 2009
*/
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_tun.h>
#define RTLD_NEXT ((void *) -1l)
static int tunfd = -1;
int open(const char *file, int flags, ...)
{
va_list ap;
mode_t mode;
static int (*oldfn_open)(const char *file, int flags, ...);
int fd;
if (oldfn_open == NULL)
oldfn_open = dlsym(RTLD_NEXT, "open");
va_start(ap, flags);
mode = va_arg(ap, mode_t);
va_end(ap);
fd = oldfn_open(file, flags, mode);
if (!strcmp(file, "/dev/net/tun"))
tunfd = fd;
return fd;
}
/* Block the call to system("/sbin/ifconfig tun...") */
int system(const char *command)
{
static int (*oldfn_system)(const char *command);
if (oldfn_system == NULL)
oldfn_system = dlsym(RTLD_NEXT, "system");
if (!strncmp("/sbin/ifconfig tun0", command, 19))
return 0;
return oldfn_system(command);
}
int ioctl(int fd, unsigned long req, ...)
{
va_list ap;
void *ioctlarg;
struct ifreq *ifr;
static int (*oldfn_ioctl)(int fd, unsigned long req, ...);
char *ifname;
if (oldfn_ioctl == NULL)
oldfn_ioctl = dlsym(RTLD_NEXT, "ioctl");
va_start(ap, req);
ioctlarg = va_arg(ap, void *);
va_end(ap);
if (req == SIOCSARP)
return 0;
if (fd != tunfd || req != TUNSETIFF)
return oldfn_ioctl(fd, req, ioctlarg);
if (!(ifname = getenv("VLM_TAP")) || strlen(ifname) >= IFNAMSIZ)
{
write(2, "Invalid VLM_TAP.\n", 20);
exit(1);
}
ifr = ioctlarg;
strncpy(ifr->ifr_name, ifname, IFNAMSIZ);
return oldfn_ioctl(fd, req, ifr);
}
Linux VLM workarounds
Linux VLM workarounds