|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <ip.h> | 
|  | #include <bio.h> | 
|  | #include <ndb.h> | 
|  |  | 
|  | static uchar noether[6]; | 
|  |  | 
|  | /* | 
|  | *  Look for a pair with the given attribute.  look first on the same line, | 
|  | *  then in the whole entry. | 
|  | */ | 
|  | static Ndbtuple* | 
|  | lookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to) | 
|  | { | 
|  | Ndbtuple *nt; | 
|  |  | 
|  | /* first look on same line (closer binding) */ | 
|  | for(nt = line;;){ | 
|  | if(strcmp(attr, nt->attr) == 0){ | 
|  | strncpy(to, nt->val, Ndbvlen); | 
|  | return nt; | 
|  | } | 
|  | nt = nt->line; | 
|  | if(nt == line) | 
|  | break; | 
|  | } | 
|  | /* search whole tuple */ | 
|  | for(nt = entry; nt; nt = nt->entry) | 
|  | if(strcmp(attr, nt->attr) == 0){ | 
|  | strncpy(to, nt->val, Ndbvlen); | 
|  | return nt; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  lookup an ip address | 
|  | */ | 
|  | static uchar* | 
|  | lookupip(Ndb *db, char *name, uchar *to, Ipinfo *iip) | 
|  | { | 
|  | Ndbtuple *t, *nt; | 
|  | char buf[Ndbvlen]; | 
|  | uchar subnet[IPaddrlen]; | 
|  | Ndbs s; | 
|  | char *attr; | 
|  |  | 
|  | attr = ipattr(name); | 
|  | if(strcmp(attr, "ip") == 0){ | 
|  | parseip(to, name); | 
|  | return to; | 
|  | } | 
|  |  | 
|  | t = ndbgetval(db, &s, attr, name, "ip", buf); | 
|  | if(t){ | 
|  | /* first look for match on same subnet */ | 
|  | for(nt = t; nt; nt = nt->entry){ | 
|  | if(strcmp(nt->attr, "ip") != 0) | 
|  | continue; | 
|  | parseip(to, nt->val); | 
|  | maskip(to, iip->ipmask, subnet); | 
|  | if(memcmp(subnet, iip->ipnet, sizeof(subnet)) == 0) | 
|  | return to; | 
|  | } | 
|  |  | 
|  | /* otherwise, just take what we have */ | 
|  | ndbfree(t); | 
|  | parseip(to, buf); | 
|  | return to; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  lookup a subnet and fill in anything we can | 
|  | */ | 
|  | static void | 
|  | recursesubnet(Ndb *db, uchar *mask, Ipinfo *iip, char *fs, char *gw, char *au) | 
|  | { | 
|  | Ndbs s; | 
|  | Ndbtuple *t; | 
|  | uchar submask[IPaddrlen]; | 
|  | char ip[Ndbvlen]; | 
|  |  | 
|  | memmove(iip->ipmask, mask, 4); | 
|  | maskip(iip->ipaddr, iip->ipmask, iip->ipnet); | 
|  | sprint(ip, "%I", iip->ipnet); | 
|  | t = ndbsearch(db, &s, "ip", ip); | 
|  | print("%s->", ip); | 
|  | if(t){ | 
|  | /* look for a further subnet */ | 
|  | if(lookval(t, s.t, "ipmask", ip)){ | 
|  | parseip(submask, ip); | 
|  |  | 
|  | /* recurse only if it has changed */ | 
|  | if(!equivip(submask, mask)) | 
|  | recursesubnet(db, submask, iip, fs, gw, au); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* fill in what we don't have */ | 
|  | if(gw[0] == 0) | 
|  | lookval(t, s.t, "ipgw", gw); | 
|  | if(fs[0] == 0) | 
|  | lookval(t, s.t, "fs", fs); | 
|  | if(au[0] == 0) | 
|  | lookval(t, s.t, "auth", au); | 
|  |  | 
|  | ndbfree(t); | 
|  | } | 
|  | } | 
|  | #ifdef foo | 
|  | /* | 
|  | *  find out everything we can about a system from what has been | 
|  | *  specified. | 
|  | */ | 
|  | int | 
|  | ipinfo(Ndb *db, char *etherin, char *ipin, char *name, Ipinfo *iip) | 
|  | { | 
|  | Ndbtuple *t; | 
|  | Ndbs s; | 
|  | char ether[Ndbvlen]; | 
|  | char ip[Ndbvlen]; | 
|  | char fsname[Ndbvlen]; | 
|  | char gwname[Ndbvlen]; | 
|  | char auname[Ndbvlen]; | 
|  |  | 
|  | memset(iip, 0, sizeof(Ipinfo)); | 
|  | fsname[0] = 0; | 
|  | gwname[0] = 0; | 
|  | auname[0] = 0; | 
|  |  | 
|  | /* | 
|  | *  look for a matching entry | 
|  | */ | 
|  | t = 0; | 
|  | if(etherin) | 
|  | t = ndbgetval(db, &s, "ether", etherin, "ip", ip); | 
|  | if(t == 0 && ipin) | 
|  | t = ndbsearch(db, &s, "ip", ipin); | 
|  | if(t == 0 && name) | 
|  | t = ndbgetval(db, &s, ipattr(name), name, "ip", ip); | 
|  | if(t){ | 
|  | /* | 
|  | *  copy in addresses and name | 
|  | */ | 
|  | if(lookval(t, s.t, "ip", ip)) | 
|  | parseip(iip->ipaddr, ip); | 
|  | if(lookval(t, s.t, "ether", ether)) | 
|  | parseether(iip->etheraddr, ether); | 
|  | lookval(t, s.t, "dom", iip->domain); | 
|  |  | 
|  | /* | 
|  | *  Look for bootfile, fs, and gateway. | 
|  | *  If necessary, search through all entries for | 
|  | *  this ip address. | 
|  | */ | 
|  | while(t){ | 
|  | if(iip->bootf[0] == 0) | 
|  | lookval(t, s.t, "bootf", iip->bootf); | 
|  | if(fsname[0] == 0) | 
|  | lookval(t, s.t, "fs", fsname); | 
|  | if(gwname[0] == 0) | 
|  | lookval(t, s.t, "ipgw", gwname); | 
|  | if(auname[0] == 0) | 
|  | lookval(t, s.t, "auth", auname); | 
|  | ndbfree(t); | 
|  | if(iip->bootf[0] && fsname[0] && gwname[0] && auname[0]) | 
|  | break; | 
|  | t = ndbsnext(&s, "ether", ether); | 
|  | } | 
|  | } else if(ipin) { | 
|  | /* | 
|  | *  copy in addresses (all we know) | 
|  | */ | 
|  | parseip(iip->ipaddr, ipin); | 
|  | if(etherin) | 
|  | parseether(iip->etheraddr, etherin); | 
|  | } else | 
|  | return -1; | 
|  |  | 
|  | /* | 
|  | *  Look up the client's network and find a subnet mask for it. | 
|  | *  Fill in from the subnet (or net) entry anything we can't figure | 
|  | *  out from the client record. | 
|  | */ | 
|  | recursesubnet(db, classmask[CLASS(iip->ipaddr)], iip, fsname, gwname, auname); | 
|  |  | 
|  | /* lookup fs's and gw's ip addresses */ | 
|  |  | 
|  | if(fsname[0]) | 
|  | lookupip(db, fsname, iip->fsip, iip); | 
|  | if(gwname[0]) | 
|  | lookupip(db, gwname, iip->gwip, iip); | 
|  | if(auname[0]) | 
|  | lookupip(db, auname, iip->auip, iip); | 
|  | return 0; | 
|  | } | 
|  | #endif | 
|  | void | 
|  | main(int argc, char **argv) | 
|  | { | 
|  | Ipinfo ii; | 
|  | Ndb *db; | 
|  |  | 
|  | db = ndbopen(0); | 
|  |  | 
|  | fmtinstall('E', eipconv); | 
|  | fmtinstall('I', eipconv); | 
|  | if(argc < 2) | 
|  | exits(0); | 
|  | if(strchr(argv[1], '.')){ | 
|  | if(ipinfo(db, 0, argv[1], 0, &ii) < 0) | 
|  | exits(0); | 
|  | } else { | 
|  | if(ipinfo(db, argv[1], 0, 0, &ii) < 0) | 
|  | exits(0); | 
|  | } | 
|  | fprint(2, "a %I m %I n %I f %s e %E\n", ii.ipaddr, | 
|  | ii.ipmask, ii.ipnet, ii.bootf, ii.etheraddr); | 
|  | } |