chiark / gitweb /
Initial checkin. Compiles but doesn't run yet.
authorian <ian>
Sat, 18 Sep 1999 20:12:47 +0000 (20:12 +0000)
committerian <ian>
Sat, 18 Sep 1999 20:12:47 +0000 (20:12 +0000)
ipif/.cvsignore [new file with mode: 0644]
ipif/Makefile [new file with mode: 0644]
ipif/service.c [new file with mode: 0644]
ipif/x.gdb [new file with mode: 0644]

diff --git a/ipif/.cvsignore b/ipif/.cvsignore
new file mode 100644 (file)
index 0000000..24e1098
--- /dev/null
@@ -0,0 +1 @@
+service
diff --git a/ipif/Makefile b/ipif/Makefile
new file mode 100644 (file)
index 0000000..fd69b4a
--- /dev/null
@@ -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 (file)
index 0000000..c1c1f71
--- /dev/null
@@ -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:
+ *  <base-prefix>/<base-prefix-len>
+ *      Specifies the base address and prefix to restrict the
+ *      addresses used to.
+ *  <gid-min>-<gid-max>:<gid-add>/<gid-mask>[,...]
+ *      The ranges specified by <gid-min> are checked <gid-max> until
+ *      one is found which matches at least one gid in USERV_GID.
+ *      Then the gid will have <gid-add> added to it and will then be
+ *      masked so that it is <gid-mask> 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.
+ *  <local-addr>,<peer-addr>,<mtu>,<proto>
+ *      As for slattach.  Supported protocols are slip, cslip, and
+ *      adaptive.  Alternatively, set to `debug' to print debugging
+ *      info.  <local-addr> is address of the interface on chiark;
+ *      <peer-addr> is the address of the point-to-point peer.
+ *  <prefix>/<mask>,<prefix>/<mask>,...
+ *      List of additional routes to add for this interface.
+ *      May be the empty argument.
+ *
+ * Should be run from userv with no-disconnect-hup.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#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<nexroutes; i++) {
+      sprintf(erwhatbuf2,"route %d",i+1);
+      addrnet_mustdiffer(erwhatbuf,routeaddr,routemask,
+                        erwhatbuf2,exroutes[i].prefix,exroutes[i].mask);
+    }
+    exroutes[nexroutes].prefix= routeaddr;
+    exroutes[nexroutes].mask= routemask;
+    ip2txt(routeaddr,exroutes[nexroutes].prefixtxt);
+    ip2txt(routemask,exroutes[nexroutes].masktxt);
+  }
+  ip2txt(localaddr,localtxt);
+  ip2txt(peeraddr,peertxt);
+  
+  if (!proto) {
+    char basetxt[ATXTLEN];
+    
+    printf("protocol: debug\n"
+          "base:     %08lx/%-2ld == %s/%ld\n"
+          "auth gid: %ld"
+          "local:    %08lx    == %s\n"
+          "peer:     %08lx    == %s\n"
+          "mtu:      %ld"
+          "routes:   %d",
+          baseprefix, basemask, ip2txt(baseprefix,basetxt), basemask,
+          tgid,
+          localaddr, localtxt,
+          peeraddr, peertxt,
+          mtu,
+          nexroutes);
+    for (i=0; i<nexroutes; i++) {
+      sprintf(erwhatbuf2, "route %d:", i+1);
+      printf("%-9s %08lx/%-2ld == %s/%s\n",
+            erwhatbuf,
+            exroutes[i].prefix, exroutes[i].mask,
+            exroutes[i].prefixtxt, exroutes[i].masktxt);
+    }
+    if (ferror(stdout) || fclose(stdout)) sysfatal("flush stdout");
+    exit(0);
+  }
+  abort();
+}
diff --git a/ipif/x.gdb b/ipif/x.gdb
new file mode 100644 (file)
index 0000000..596272f
--- /dev/null
@@ -0,0 +1,2 @@
+set environment USERV_GID="5000 5001"
+set args 10.232.0.0/15 5000-8999:0/5 -- 10.232.40.0,10.232.40.1,1500,debug ""