URI:
       tndbipinfo.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tndbipinfo.c (4880B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ndb.h>
            5 #include <ip.h>
            6 
            7 enum
            8 {
            9         Ffound=        1<<0,
           10         Fignore=        1<<1,
           11         Faddr=        1<<2
           12 };
           13 
           14 static Ndbtuple*        filter(Ndb *db, Ndbtuple *t, Ndbtuple *f);
           15 static Ndbtuple*        mkfilter(int argc, char **argv);
           16 static int                filtercomplete(Ndbtuple *f);
           17 static int                prefixlen(uchar *ip);
           18 static Ndbtuple*        subnet(Ndb *db, uchar *net, Ndbtuple *f, int prefix);
           19 
           20 /* make a filter to be used in filter */
           21 static Ndbtuple*
           22 mkfilter(int argc, char **argv)
           23 {
           24         Ndbtuple *t, *first, *last;
           25         char *p;
           26 
           27         last = first = nil;
           28         while(argc-- > 0){
           29                 t = ndbnew(0, 0);
           30                 if(first)
           31                         last->entry = t;
           32                 else
           33                         first = t;
           34                 last = t;
           35                 p = *argv++;
           36                 if(*p == '@'){
           37                         t->ptr |= Faddr;
           38                         p++;
           39                 }
           40                 strncpy(t->attr, p, sizeof(t->attr)-1);
           41         }
           42         return first;
           43 }
           44 
           45 /* return true if every pair of filter has been used */
           46 static int
           47 filtercomplete(Ndbtuple *f)
           48 {
           49         for(; f; f = f->entry)
           50                 if((f->ptr & Fignore) == 0)
           51                         return 0;
           52         return 1;
           53 }
           54 
           55 /* set the attribute of all entries in a tuple */
           56 static Ndbtuple*
           57 setattr(Ndbtuple *t, char *attr)
           58 {
           59         Ndbtuple *nt;
           60 
           61         for(nt = t; nt; nt = nt->entry)
           62                 strcpy(nt->attr, attr);
           63         return t;
           64 }
           65 
           66 /*
           67  *  return only the attr/value pairs in t maching the filter, f.
           68  *  others are freed.  line structure is preserved.
           69  */
           70 static Ndbtuple*
           71 filter(Ndb *db, Ndbtuple *t, Ndbtuple *f)
           72 {
           73         Ndbtuple *nt, *nf, *next;
           74 
           75         /* filter out what we don't want */
           76         for(nt = t; nt; nt = next){
           77                 next = nt->entry;
           78 
           79                 /* look through filter */
           80                 for(nf = f; nf != nil; nf = nf->entry){
           81                         if(!(nf->ptr&Fignore) && strcmp(nt->attr, nf->attr) == 0)
           82                                 break;
           83                 }
           84                 if(nf == nil){
           85                         /* remove nt from t */
           86                         t = ndbdiscard(t, nt);
           87                 } else {
           88                         if(nf->ptr & Faddr)
           89                                 t = ndbsubstitute(t, nt, setattr(ndbgetipaddr(db, nt->val), nt->attr));
           90                         nf->ptr |= Ffound;
           91                 }
           92         }
           93 
           94         /* remember filter etnries that matched */
           95         for(nf = f; nf != nil; nf = nf->entry)
           96                 if(nf->ptr & Ffound)
           97                         nf->ptr = (nf->ptr & ~Ffound) | Fignore;
           98 
           99         return t;
          100 }
          101 
          102 static int
          103 prefixlen(uchar *ip)
          104 {
          105         int y, i;
          106 
          107         for(y = IPaddrlen-1; y >= 0; y--)
          108                 for(i = 8; i > 0; i--)
          109                         if(ip[y] & (1<<(8-i)))
          110                                 return y*8 + i;
          111         return 0;
          112 }
          113 
          114 /*
          115  *  look through a containing subset
          116  */
          117 static Ndbtuple*
          118 subnet(Ndb *db, uchar *net, Ndbtuple *f, int prefix)
          119 {
          120         Ndbs s;
          121         Ndbtuple *t, *nt, *xt;
          122         char netstr[128];
          123         uchar mask[IPaddrlen];
          124         int masklen;
          125 
          126         t = nil;
          127         sprint(netstr, "%I", net);
          128         nt = ndbsearch(db, &s, "ip", netstr);
          129         while(nt != nil){
          130                 xt = ndbfindattr(nt, nt, "ipnet");
          131                 if(xt){
          132                         xt = ndbfindattr(nt, nt, "ipmask");
          133                         if(xt)
          134                                 parseipmask(mask, xt->val);
          135                         else
          136                                 ipmove(mask, defmask(net));
          137                         masklen = prefixlen(mask);
          138                         if(masklen <= prefix)
          139                                 t = ndbconcatenate(t, filter(db, nt, f));
          140                 } else
          141                         ndbfree(nt);
          142                 nt = ndbsnext(&s, "ip", netstr);
          143         }
          144         return t;
          145 }
          146 
          147 /*
          148  *  fill in all the requested attributes for a system.
          149  *  if the system's entry doesn't have all required,
          150  *  walk through successively more inclusive networks
          151  *  for inherited attributes.
          152  */
          153 Ndbtuple*
          154 ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
          155 {
          156         Ndbtuple *t, *nt, *f;
          157         Ndbs s;
          158         char *ipstr;
          159         uchar net[IPaddrlen];
          160         uchar ip[IPaddrlen];
          161         int prefix, smallestprefix;
          162         int force;
          163 
          164         /* just in case */
          165         fmtinstall('I', eipfmt);
          166         fmtinstall('M', eipfmt);
          167 
          168         /* get needed attributes */
          169         f = mkfilter(n, alist);
          170 
          171         /*
          172          *  first look for a matching entry with an ip address
          173          */
          174         t = nil;
          175         ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt);
          176         if(ipstr == nil){
          177                 /* none found, make one up */
          178                 if(strcmp(attr, "ip") != 0)
          179                         return nil;
          180                 t = ndbnew("ip", val);
          181                 t->line = t;
          182                 t->entry = nil;
          183                 parseip(net, val);
          184         } else {
          185                 /* found one */
          186                 while(nt != nil){
          187                         nt = ndbreorder(nt, s.t);
          188                         t = ndbconcatenate(t, nt);
          189                         nt = ndbsnext(&s, attr, val);
          190                 }
          191                 parseip(net, ipstr);
          192                 free(ipstr);
          193         }
          194         ipmove(ip, net);
          195         t = filter(db, t, f);
          196 
          197         /*
          198          *  now go through subnets to fill in any missing attributes
          199          */
          200         if(isv4(net)){
          201                 prefix = 127;
          202                 smallestprefix = 100;
          203                 force = 0;
          204         } else {
          205                 /* in v6, the last 8 bytes have no structure (we hope) */
          206                 prefix = 64;
          207                 smallestprefix = 2;
          208                 memset(net+8, 0, 8);
          209                 force = 1;
          210         }
          211 
          212         /*
          213          *  to find a containing network, keep turning off
          214          *  the lower bit and look for a network with
          215          *  that address and a shorter mask.  tedius but
          216          *  complete, we may need to find a trick to speed this up.
          217          */
          218         for(; prefix >= smallestprefix; prefix--){
          219                 if(filtercomplete(f))
          220                         break;
          221                 if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0)
          222                         continue;
          223                 force = 0;
          224                 net[prefix/8] &= ~(1<<(7-(prefix%8)));
          225                 t = ndbconcatenate(t, subnet(db, net, f, prefix));
          226         }
          227 
          228         /*
          229          *  if there's an unfulfilled ipmask, make one up
          230          */
          231         nt = ndbfindattr(f, f, "ipmask");
          232         if(nt && !(nt->ptr & Fignore)){
          233                 char x[64];
          234 
          235                 snprint(x, sizeof(x), "%M", defmask(ip));
          236                 t = ndbconcatenate(t, ndbnew("ipmask", x));
          237         }
          238 
          239         ndbfree(f);
          240         return t;
          241 }