akaros/user/ndblib/ndbipinfo.c
<<
>>
Prefs
   1/* 
   2 * This file is part of the UCB release of Plan 9. It is subject to the license
   3 * terms in the LICENSE file found in the top-level directory of this
   4 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   5 * part of the UCB release of Plan 9, including this file, may be copied,
   6 * modified, propagated, or distributed except according to the terms contained
   7 * in the LICENSE file.
   8 */
   9#include <stdlib.h>
  10
  11#include <stdio.h>
  12#include <parlib/parlib.h>
  13#include <unistd.h>
  14#include <signal.h>
  15#include <fcntl.h>
  16#include <iplib/iplib.h>
  17#include <ndblib/ndb.h>
  18
  19enum
  20{
  21        Ffound= 1<<0,
  22        Fignore=1<<1,
  23        Faddr=  1<<2,
  24};
  25
  26static struct ndbtuple* filter(struct ndb *db, struct ndbtuple *t,
  27                                      struct ndbtuple *f);
  28static struct ndbtuple* mkfilter(int argc, char **argv);
  29static int              filtercomplete(struct ndbtuple *f);
  30static struct ndbtuple* toipaddr(struct ndb *db, struct ndbtuple *t);
  31static int              prefixlen(uint8_t *ip);
  32static struct ndbtuple* subnet(struct ndb *db, uint8_t *net,
  33                                      struct ndbtuple *f, int prefix);
  34
  35/* make a filter to be used in filter */
  36static struct ndbtuple*
  37mkfilter(int argc, char **argv)
  38{
  39        struct ndbtuple *t, *first, *last;
  40        char *p;
  41
  42        last = first = NULL;
  43        while(argc-- > 0){
  44                t = ndbnew(0, 0);
  45                if(first)
  46                        last->entry = t;
  47                else
  48                        first = t;
  49                last = t;
  50                p = *argv++;
  51                if (*p == '@'){         /* @attr=val ? */
  52                        t->ptr |= Faddr;/* return resolved address(es) */
  53                        p++;
  54                }
  55                strncpy(t->attr, p, sizeof(t->attr)-1);
  56        }
  57        ndbsetmalloctag(first, getcallerpc(&argc));
  58        return first;
  59}
  60
  61/* return true if every pair of filter has been used */
  62static int
  63filtercomplete(struct ndbtuple *f)
  64{
  65        for(; f; f = f->entry)
  66                if((f->ptr & Fignore) == 0)
  67                        return 0;
  68        return 1;
  69}
  70
  71/* set the attribute of all entries in a tuple */
  72static struct ndbtuple*
  73setattr(struct ndbtuple *t, char *attr)
  74{
  75        struct ndbtuple *nt;
  76
  77        for(nt = t; nt; nt = nt->entry)
  78                strcpy(nt->attr, attr);
  79        return t;
  80}
  81
  82/*
  83 *  return only the attr/value pairs in t maching the filter, f.
  84 *  others are freed.  line structure is preserved.
  85 */
  86static struct ndbtuple*
  87filter(struct ndb *db, struct ndbtuple *t, struct ndbtuple *f)
  88{
  89        struct ndbtuple *nt, *nf, *next;
  90
  91        /* filter out what we don't want */
  92        for(nt = t; nt; nt = next){
  93                next = nt->entry;
  94
  95                /* look through filter */
  96                for(nf = f; nf != NULL; nf = nf->entry){
  97                        if (!(nf->ptr&Fignore) && strcmp(nt->attr, nf->attr) ==
  98                           0)
  99                                break;
 100                }
 101                if(nf == NULL){
 102                        /* remove nt from t */
 103                        t = ndbdiscard(t, nt);
 104                } else {
 105                        if (nf->ptr & Faddr)
 106                                t = ndbsubstitute(t, nt,
 107                                                  setattr(ndbgetipaddr(db,
 108                                                                       nt->val),
 109                                                          nt->attr));
 110                        nf->ptr |= Ffound;
 111                }
 112        }
 113
 114        /* remember filter etnries that matched */
 115        for(nf = f; nf != NULL; nf = nf->entry)
 116                if(nf->ptr & Ffound)
 117                        nf->ptr = (nf->ptr & ~Ffound) | Fignore;
 118
 119        ndbsetmalloctag(t, getcallerpc(&db));
 120        return t;
 121}
 122
 123static int
 124prefixlen(uint8_t *ip)
 125{
 126        int y, i;
 127
 128        for(y = IPaddrlen-1; y >= 0; y--)
 129                for(i = 8; i > 0; i--)
 130                        if(ip[y] & (1<<(8-i)))
 131                                return y*8 + i;
 132        return 0;
 133}
 134
 135/*
 136 *  look through a containing subset
 137 */
 138static struct ndbtuple*
 139subnet(struct ndb *db, uint8_t *net, struct ndbtuple *f, int prefix)
 140{
 141        struct ndbs s;
 142        struct ndbtuple *t, *nt, *xt;
 143        char netstr[128];
 144        uint8_t mask[IPaddrlen];
 145        int masklen;
 146
 147        t = NULL;
 148        sprintf(netstr, "%I", net);
 149        nt = ndbsearch(db, &s, "ip", netstr);
 150        while(nt != NULL){
 151                xt = ndbfindattr(nt, nt, "ipnet");
 152                if(xt){
 153                        xt = ndbfindattr(nt, nt, "ipmask");
 154                        if(xt)
 155                                parseipmask(mask, xt->val);
 156                        else
 157                                ipmove(mask, defmask(net));
 158                        masklen = prefixlen(mask);
 159                        if(masklen <= prefix){
 160                                t = ndbconcatenate(t, filter(db, nt, f));
 161                                nt = NULL;
 162                        }
 163                }
 164                ndbfree(nt);
 165                nt = ndbsnext(&s, "ip", netstr);
 166        }
 167        ndbsetmalloctag(t, getcallerpc(&db));
 168        return t;
 169}
 170
 171/*
 172 *  fill in all the requested attributes for a system.
 173 *  if the system's entry doesn't have all required,
 174 *  walk through successively more inclusive networks
 175 *  for inherited attributes.
 176 */
 177struct ndbtuple*
 178ndbipinfo(struct ndb *db, char *attr, char *val, char **alist, int n)
 179{
 180        struct ndbtuple *t, *nt, *f;
 181        struct ndbs s;
 182        char *ipstr;
 183        uint8_t net[IPaddrlen], ip[IPaddrlen];
 184        int prefix, smallestprefix, force;
 185        int64_t r;
 186
 187#if 0
 188        /* just in case */
 189        fmtinstall('I', eipfmt);
 190        fmtinstall('M', eipfmt);
 191#endif
 192
 193        /* get needed attributes */
 194        f = mkfilter(n, alist);
 195
 196        /*
 197         *  first look for a matching entry with an ip address
 198         */
 199        t = NULL;
 200        ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt);
 201        if(ipstr == NULL){
 202                /* none found, make one up */
 203                if(strcmp(attr, "ip") != 0) {
 204                        ndbfree(f);
 205                        return NULL;    
 206                }
 207                t = ndbnew("ip", val);
 208                t->line = t;
 209                t->entry = NULL;
 210                r = parseip(net, val);
 211                if(r == -1)
 212                        ndbfree(t);
 213        } else {
 214                /* found one */
 215                while(nt != NULL){
 216                        nt = ndbreorder(nt, s.t);
 217                        t = ndbconcatenate(t, nt);
 218                        nt = ndbsnext(&s, attr, val);
 219                }
 220                r = parseip(net, ipstr);
 221                free(ipstr);
 222        }
 223        if(r < 0){
 224                ndbfree(f);
 225                return NULL;
 226        }
 227        ipmove(ip, net);
 228        t = filter(db, t, f);
 229
 230        /*
 231         *  now go through subnets to fill in any missing attributes
 232         */
 233        if(isv4(net)){
 234                prefix = 127;
 235                smallestprefix = 100;
 236                force = 0;
 237        } else {
 238                /* in v6, the last 8 bytes have no structure (we hope) */
 239                prefix = 64;
 240                smallestprefix = 2;
 241                memset(net+8, 0, 8);
 242                force = 1;
 243        }
 244
 245        /*
 246         *  to find a containing network, keep turning off
 247         *  the lower bit and look for a network with
 248         *  that address and a shorter mask.  tedius but
 249         *  complete, we may need to find a trick to speed this up.
 250         */
 251        for(; prefix >= smallestprefix; prefix--){
 252                if(filtercomplete(f))
 253                        break;
 254                if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0)
 255                        continue;
 256                force = 0;
 257                net[prefix/8] &= ~(1<<(7-(prefix%8)));
 258                t = ndbconcatenate(t, subnet(db, net, f, prefix));
 259        }
 260
 261        /*
 262         *  if there's an unfulfilled ipmask, make one up
 263         */
 264        nt = ndbfindattr(f, f, "ipmask");
 265        if(nt && !(nt->ptr & Fignore)){
 266                char x[64];
 267
 268                snprintf(x, sizeof(x), "%M", defmask(ip));
 269                t = ndbconcatenate(t, ndbnew("ipmask", x));
 270        }
 271
 272        ndbfree(f);
 273        ndbsetmalloctag(t, getcallerpc(&db));
 274        return t;
 275}
 276