From 1c1a9fa137045a9ac8cca121cd7ed89be5fe43e0 Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 18 Sep 1999 20:12:47 +0000 Subject: [PATCH] Initial checkin. Compiles but doesn't run yet. --- ipif/.cvsignore | 1 + ipif/Makefile | 6 + ipif/service.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++ ipif/x.gdb | 2 + 4 files changed, 302 insertions(+) create mode 100644 ipif/.cvsignore create mode 100644 ipif/Makefile create mode 100644 ipif/service.c create mode 100644 ipif/x.gdb diff --git a/ipif/.cvsignore b/ipif/.cvsignore new file mode 100644 index 0000000..24e1098 --- /dev/null +++ b/ipif/.cvsignore @@ -0,0 +1 @@ +service diff --git a/ipif/Makefile b/ipif/Makefile new file mode 100644 index 0000000..fd69b4a --- /dev/null +++ b/ipif/Makefile @@ -0,0 +1,6 @@ +# + +CFLAGS= -Wall -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith \ + -Wwrite-strings -g + +all: service diff --git a/ipif/service.c b/ipif/service.c new file mode 100644 index 0000000..c1c1f71 --- /dev/null +++ b/ipif/service.c @@ -0,0 +1,293 @@ +/* + * userv service (or standalone program) + * for per-user IP subranges. + * + * This is invoked as root, directly from userv. + * Its arguments are supposed to be, in order: + * / + * Specifies the base address and prefix to restrict the + * addresses used to. + * -:/[,...] + * The ranges specified by are checked until + * one is found which matches at least one gid in USERV_GID. + * Then the gid will have added to it and will then be + * masked so that it is long (higher set bits are + * discarded). The result is added to the base prefix. It is an + * error for no gid to match. Alternatively, if this argument + * is `*' then USERV_GID is not checked. + * -- Indicates that the remaining arguments are user-supplied + * and therefore untrusted. + * ,,, + * As for slattach. Supported protocols are slip, cslip, and + * adaptive. Alternatively, set to `debug' to print debugging + * info. is address of the interface on chiark; + * is the address of the point-to-point peer. + * /,/,... + * List of additional routes to add for this interface. + * May be the empty argument. + * + * Should be run from userv with no-disconnect-hup. + */ + +#include +#include +#include +#include +#include + +#define NARGS 5 +#define MAXEXROUTES 5 +#define ATXTLEN 12 + +static const char *proto; +static unsigned long baseprefix, basemask; +static unsigned long localaddr, peeraddr, mtu; +static int nexroutes; +static struct exroute { + unsigned long prefix, mask; + char prefixtxt[ATXTLEN], masktxt[ATXTLEN]; +} exroutes[MAXEXROUTES]; + +char localtxt[ATXTLEN]; +char peertxt[ATXTLEN]; + +static void fatal(const char *msg) { + fprintf(stderr,"userv-ipif: service: fatal error: %s\n",msg); + exit(8); +} + +static void sysfatal(const char *msg) { + fprintf(stderr,"userv-ipif: service: fatal system error: %s: %s\n", + msg, strerror(errno)); + exit(12); +} + +static void badusage(void) { + fputs("userv-ipif: service: bad usage or permission denied\n",stderr); + exit(16); +} + +static char *ip2txt(unsigned long addr, char *buf) { + sprintf(buf, "%lu.%lu.%lu.%lu", + (addr>>24) & 0x0ff, + (addr>>16) & 0x0ff, + (addr>>8) & 0x0ff, + (addr) & 0x0ff); + return buf; +} + +static unsigned long eat_number(const char **argp, const char *what, + unsigned long min, unsigned long max, + const char *endchars, int *endchar_r) { + /* If !endchars then the endchar must be a nul, otherwise it may be + * a nul (resulting in *argp set to 0) or something else (*argp set + * to point to after delim, *endchar_r set to delim). + * *endchar_r may be 0. + */ + unsigned long rv; + char *ep; + int endchar; + + if (!*argp) { fprintf(stderr,"missing number %s\n",what); badusage(); } + rv= strtoul(*argp,&ep,0); + if ((endchar= *ep)) { + if (!endchars) { fprintf(stderr,"junk after number %s\n",what); badusage(); } + if (!strchr(endchars,endchar)) { + fprintf(stderr,"invalid delimiter %c after number %s: expected %s (or none?)\n", + endchar,what,endchars); + badusage(); + } + *argp= ep+1; + } else { + *argp= 0; + } + if (endchar_r) *endchar_r= endchar; + if (rv < min || rv > max) { + fprintf(stderr,"number %s value %lu out of range %lu..%lu", + what, rv, min, max); + badusage(); + } + return rv; +} + +static void addrnet_mustbein(const char *what, + unsigned long prefix, unsigned long mask, + unsigned long mprefix, unsigned long mmask) { + if (!(~mask & mmask) && (prefix & mmask) == mprefix) return; + fprintf(stderr, "%s %08lx/%08lx not in required subspace %08lx/%08lx\n", + what, prefix, mask, mprefix, mmask); + badusage(); +} + +static void addrnet_mustdiffer(const char *w1, unsigned long p1, unsigned long m1, + const char *w2, unsigned long p2, unsigned long m2) { + unsigned long mask; + + mask= m1&m2; + if ((p1 & mask) != (p2 & mask)) return; + fprintf(stderr, "%s %08lx/%08lx overlaps/clashes with %s %08lx/%08lx", + w1,p1,m1, w2,p2,m2); + badusage(); +} + +static unsigned long eat_addr(const char **argp, const char *what, + unsigned long mprefix, unsigned long mmask, + const char *endchars, int *endchar_r) { + char whatbuf[100]; + unsigned long rv; + int i; + + assert(!(~mmask & mprefix)); + + for (rv=0, i=0; + i<4; + i++) { + rv <<= 8; + sprintf(whatbuf,"%s byte #%d",what,i); + rv |= eat_number(argp,whatbuf, 0,255, i<3 ? "." : endchars, endchar_r); + } + + addrnet_mustbein(what,rv,~0UL, mprefix,mmask); + return rv; +} + +static void eat_prefixmask(const char **argp, const char *what, + unsigned long mprefix, unsigned long mmask, + const char *endchars, int *endchar_r, + unsigned long *prefix_r, unsigned long *mask_r, int *len_r) { + /* mask_r and len_r may be 0 */ + char whatbuf[100]; + int len; + unsigned long prefix, mask; + + prefix= eat_addr(argp,what, 0,0, "/",0); + sprintf(whatbuf,"%s length",what); + len= eat_number(argp,whatbuf, 0,32, endchars,endchar_r); + + mask= (~0UL << (32-len)); + if (prefix & ~mask) { + fprintf(stderr,"%s prefix %08lx not fully contained in mask %08lx\n", + what,prefix,mask); + badusage(); + } + addrnet_mustbein(what,prefix,mask, mprefix,mmask); + *prefix_r= prefix; + if (mask_r) *mask_r= mask; + if (len_r) *len_r= len; +} + +int main(int argc, const char *const *argv) { + static unsigned long gidmaxval= (unsigned long)((gid_t)-2); + static const char *const protos_ok[]= { "slip", "cslip", "adaptive", 0 }; + + unsigned long gidmin, gidmax, gidadd; + int baselen; + unsigned long routeaddr, routemask, tgid; + const char *carg, *gidlist; + const char *const *cprotop; + int gidlen, i; + char erwhatbuf[100], erwhatbuf2[100]; + + if (argc < NARGS+1) { fputs("too few arguments\n",stderr); badusage(); } + if (argc > NARGS+1) { fputs("too many arguments\n",stderr); badusage(); } + + carg= *++argv; + eat_prefixmask(&carg,"base", 0UL,0UL, 0,0, &baseprefix, &basemask, &baselen); + + carg= *++argv; + if (!strcmp(carg,"*")) { + for (;;) { + if (!*carg) fatal("no gid authorised"); + gidmin= eat_number(&carg,"gid-min", 0,gidmaxval, "-",0); + gidmax= eat_number(&carg,"gid-max", gidmin,gidmaxval, ":",0); + gidadd= eat_number(&carg,"gid-add", 0,gidmaxval, "/",0); + gidlen= eat_number(&carg,"gid-len", 0,32-baselen, 0,0); + + gidlist= getenv("USERV_GID"); + if (!gidlist) fatal("USERV_GID not set"); + while (gidlist) { + tgid= eat_number(&gidlist,"userv_gid", 0,gidmaxval, " ",0); + if (tgid >= gidmin && tgid <= gidmax) goto gid_found; + } + } + gid_found: + tgid += gidadd; + tgid &= ((1UL << gidlen) - 1); + baselen += gidlen; + baseprefix |= (tgid << (32-baselen)); + basemask = (~0UL << (32-baselen)); + } else { + tgid= 0; + } + + carg= *++argv; + + localaddr= eat_addr(&carg,"local-addr", baseprefix,basemask, ",",0); + peeraddr= eat_addr(&carg,"peer-addr", baseprefix,basemask, ",",0); + mtu= eat_number(&carg,"mtu", 576,65536, ",",0); + + if (!strcmp(carg,"debug")) { + proto= 0; + } else { + for (cprotop= protos_ok; + (proto= *cprotop) && strcmp(proto,carg); + cprotop++); + if (!proto) fatal("invalid protocol"); + } + + addrnet_mustdiffer("local-addr",localaddr,~0UL, "peer-addr",peeraddr,~0UL); + + carg= *++argv; + for (nexroutes=0; + *carg; + carg++, nexroutes++) { + if (nexroutes == MAXEXROUTES) { + fprintf(stderr,"only %d extra routes allowed\n",MAXEXROUTES); + fatal("too many extra routes"); + } + sprintf(erwhatbuf,"route %d",nexroutes+1); + + eat_prefixmask(&carg,erwhatbuf, baseprefix,basemask, ",",0, &routeaddr,&routemask,0); + addrnet_mustdiffer(erwhatbuf,routeaddr,routemask, "local-addr",localaddr,~0UL); + addrnet_mustdiffer(erwhatbuf,routeaddr,routemask, "peer-addr",peeraddr,~0UL); + for (i=0; i