/* * lookup a telephone number */ static struct ndbtuple *telcolookup(struct network *np, char *host, char *serv, int nolookup) { struct ndbtuple *t; struct ndbs s; werrstr("can't translate address"); free(ndbgetvalue(db, &s, "sys", host, "telco", &t)); if (t == 0) return ndbnew("telco", host); return reorder(t, s.t); }
/* * parse a single tuple */ char* _ndbparsetuple(char *cp, Ndbtuple **tp) { char *p; int len; Ndbtuple *t; /* a '#' starts a comment lasting till new line */ EATWHITE(cp); if(*cp == '#' || *cp == '\n') return 0; t = ndbnew(nil, nil); setmalloctag(t, getcallerpc()); *tp = t; /* parse attribute */ p = cp; while(*cp != '=' && !ISWHITE(*cp) && *cp != '\n') cp++; len = cp - p; if(len >= Ndbalen) len = Ndbalen-1; strncpy(t->attr, p, len); /* parse value */ EATWHITE(cp); if(*cp == '='){ cp++; if(*cp == '"'){ p = ++cp; while(*cp != '\n' && *cp != '"') cp++; len = cp - p; if(*cp == '"') cp++; } else if(*cp == '#'){ len = 0; } else { p = cp; while(!ISWHITE(*cp) && *cp != '\n') cp++; len = cp - p; } ndbsetval(t, p, len); } return cp; }
/* return list of ip addresses for a name */ Ndbtuple* ndbgetipaddr(Ndb *db, char *val) { char *attr, *p; Ndbtuple *it, *first, *last, *next; Ndbs s; /* already an IP address? */ attr = ipattr(val); if(strcmp(attr, "ip") == 0){ it = ndbnew("ip", val); ndbsetmalloctag(it, getcallerpc(&db)); return it; } /* look it up */ p = ndbgetvalue(db, &s, attr, val, "ip", &it); if(p == nil) return nil; free(p); /* remove the non-ip entries */ first = last = nil; for(; it; it = next){ next = it->entry; if(strcmp(it->attr, "ip") == 0){ if(first == nil) first = it; else last->entry = it; it->entry = nil; it->line = first; last = it; } else { it->entry = nil; ndbfree(it); } } ndbsetmalloctag(first, getcallerpc(&db)); return first; }
static Ndbtuple* ndbcopy(Ndb *db, Ndbtuple *from_t, Ndbs *from_s, Ndbs *to_s) { Ndbtuple *first, *to_t, *last, *line; int newline; *to_s = *from_s; to_s->t = nil; to_s->db = db; newline = 1; last = nil; first = nil; line = nil; for(; from_t != nil; from_t = from_t->entry){ to_t = ndbnew(from_t->attr, from_t->val); /* have s point to matching tuple */ if(from_s->t == from_t) to_s->t = to_t; if(newline) line = to_t; else last->line = to_t; if(last != nil) last->entry = to_t; else { first = to_t; line = to_t; } to_t->entry = nil; to_t->line = line; last = to_t; newline = from_t->line != from_t->entry; } ndbsetmalloctag(first, getcallerpc(&db)); return first; }
/* make a filter to be used in filter */ static Ndbtuple* mkfilter(int argc, char **argv) { Ndbtuple *t, *first, *last; char *p; last = first = nil; while(argc-- > 0){ t = ndbnew(0, 0); if(first) last->entry = t; else first = t; last = t; p = *argv++; if(*p == '@'){ t->ptr |= Faddr; p++; } strncpy(t->attr, p, sizeof(t->attr)-1); } return first; }
/* make a filter to be used in filter */ static Ndbtuple* mkfilter(int argc, char **argv) { Ndbtuple *t, *first, *last; char *p; last = first = nil; while(argc-- > 0){ t = ndbnew(0, 0); if(first) last->entry = t; else first = t; last = t; p = *argv++; if(*p == '@'){ /* @attr=val ? */ t->ptr |= Faddr; /* return resolved address(es) */ p++; } strncpy(t->attr, p, sizeof(t->attr)-1); } ndbsetmalloctag(first, getcallerpc(&argc)); return first; }
/* * fill in all the requested attributes for a system. * if the system's entry doesn't have all required, * walk through successively more inclusive networks * for inherited attributes. */ Ndbtuple* ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n) { Ndbtuple *t, *nt, *f; Ndbs s; char *ipstr; uint8_t net[IPaddrlen], ip[IPaddrlen]; int prefix, smallestprefix, force; int64_t r; /* just in case */ fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); /* get needed attributes */ f = mkfilter(n, alist); /* * first look for a matching entry with an ip address */ t = nil; ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt); if(ipstr == nil){ /* none found, make one up */ if(strcmp(attr, "ip") != 0) { ndbfree(f); return nil; } t = ndbnew("ip", val); t->line = t; t->entry = nil; r = parseip(net, val); if(r == -1) ndbfree(t); } else { /* found one */ while(nt != nil){ nt = ndbreorder(nt, s.t); t = ndbconcatenate(t, nt); nt = ndbsnext(&s, attr, val); } r = parseip(net, ipstr); free(ipstr); } if(r < 0){ ndbfree(f); return nil; } ipmove(ip, net); t = filter(db, t, f); /* * now go through subnets to fill in any missing attributes */ if(isv4(net)){ prefix = 127; smallestprefix = 100; force = 0; } else { /* in v6, the last 8 bytes have no structure (we hope) */ prefix = 64; smallestprefix = 2; memset(net+8, 0, 8); force = 1; } /* * to find a containing network, keep turning off * the lower bit and look for a network with * that address and a shorter mask. tedius but * complete, we may need to find a trick to speed this up. */ for(; prefix >= smallestprefix; prefix--){ if(filtercomplete(f)) break; if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0) continue; force = 0; net[prefix/8] &= ~(1<<(7-(prefix%8))); t = ndbconcatenate(t, subnet(db, net, f, prefix)); } /* * if there's an unfulfilled ipmask, make one up */ nt = ndbfindattr(f, f, "ipmask"); if(nt && !(nt->ptr & Fignore)){ char x[64]; snprint(x, sizeof(x), "%M", defmask(ip)); t = ndbconcatenate(t, ndbnew("ipmask", x)); } ndbfree(f); ndbsetmalloctag(t, getcallerpc(&db)); return t; }
/* * lookup (and translate) an ip destination */ static struct ndbtuple *iplookup(struct network *np, char *host, char *serv, int nolookup) { char *attr, *dnsname; struct ndbtuple *t, *nt; struct ndbs s; char ts[Maxservice]; char dollar[Maxhost]; uint8_t ip[IPaddrlen]; uint8_t net[IPaddrlen]; uint8_t tnet[IPaddrlen]; struct ipifc *ifc; struct iplifc *lifc; /* * start with the service since it's the most likely to fail * and costs the least */ werrstr("can't translate address"); if (serv == 0 || ipserv(np, serv, ts, sizeof(ts)) == 0) { werrstr("can't translate service"); return 0; } /* for dial strings with no host */ if (strcmp(host, "*") == 0) return ndbnew("ip", "*"); /* * hack till we go v6 :: = 0.0.0.0 */ if (strcmp("::", host) == 0) return ndbnew("ip", "*"); /* * '$' means the rest of the name is an attribute that we * need to search for */ if (*host == '$') { if (ipattrlookup(db, ipaddr, host + 1, dollar, sizeof(dollar))) host = dollar; } /* * turn '[ip address]' into just 'ip address' */ if (*host == '[' && host[strlen(host) - 1] == ']') { host++; host[strlen(host) - 1] = 0; } /* * just accept addresses */ attr = ipattr(host); if (strcmp(attr, "ip") == 0) return ndbnew("ip", host); /* * give the domain name server the first opportunity to * resolve domain names. if that fails try the database. */ t = 0; werrstr("can't translate address"); if (strcmp(attr, "dom") == 0) t = dnsiplookup(host, &s); if (t == 0) free(ndbgetvalue(db, &s, attr, host, "ip", &t)); if (t == 0) { dnsname = ndbgetvalue(db, &s, attr, host, "dom", NULL); if (dnsname) { t = dnsiplookup(dnsname, &s); free(dnsname); } } if (t == 0) t = dnsiplookup(host, &s); if (t == 0) return 0; /* * reorder the tuple to have the matched line first and * save that in the request structure. */ t = reorder(t, s.t); /* * reorder according to our interfaces */ spinlock_lock(&ipifclock); for (ifc = ipifcs; ifc != NULL; ifc = ifc->next) { for (lifc = ifc->lifc; lifc != NULL; lifc = lifc->next) { maskip(lifc->ip, lifc->mask, net); for (nt = t; nt; nt = nt->entry) { if (strcmp(nt->attr, "ip") != 0) continue; parseip(ip, nt->val); maskip(ip, lifc->mask, tnet); if (memcmp(net, tnet, IPaddrlen) == 0) { t = reorder(t, nt); spinlock_unlock(&ipifclock); return t; } } } } spinlock_unlock(&ipifclock); return t; }