/* * call the dns process and have it try to translate a name */ static struct ndbtuple *dnsiplookup(char *host, struct ndbs *s) { char buf[Maxreply]; struct ndbtuple *t; spinlock_unlock(&dblock); /* save the name */ snprintf(buf, sizeof(buf), "%s", host); if (strcmp(ipattr(buf), "ip") == 0) t = dnsquery(mntpt, buf, "ptr"); else { t = dnsquery(mntpt, buf, "ip"); /* special case: query ipv6 (AAAA dns RR) too */ if (ipv6lookups) t = dnsip6lookup(mntpt, buf, t); } s->t = t; if (t == NULL) { snprintf(buf, sizeof(buf), "%r"); if (strstr(buf, "exist")) werrstr("can't translate address: %s", buf); else if (strstr(buf, "dns failure")) werrstr("temporary problem: %s", buf); } spinlock_lock(&dblock); return t; }
/* * lookup an ip address */ static int getipaddr(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 1; } 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 1; } /* otherwise, just take what we have */ ndbfree(t); parseip(to, buf); return 1; } return 0; }
int rmtdns(char *net, char *path) { int fd, n, nb, r; char *domain, *cp, buf[Maxdomain + 5]; if(net == 0 || path == 0) return 0; domain = strdup(path); cp = strchr(domain, '!'); if(cp){ *cp = 0; n = cp-domain; } else n = strlen(domain); if(*domain == '[' && domain[n-1] == ']'){ /* accept [nnn.nnn.nnn.nnn] */ domain[n-1] = 0; r = strcmp(ipattr(domain+1), "ip"); domain[n-1] = ']'; } else r = strcmp(ipattr(domain), "ip"); /* accept nnn.nnn.nnn.nnn */ if(r == 0){ free(domain); return 0; } snprint(buf, sizeof buf, "%s/dns", net); fd = open(buf, ORDWR); /* look up all others */ if(fd < 0){ /* dns screw up - can't check */ free(domain); return 0; } n = snprint(buf, sizeof buf, "%s all", domain); free(domain); seek(fd, 0, 0); nb = write(fd, buf, n); close(fd); if(nb != n){ rerrstr(buf, sizeof buf); if (strcmp(buf, "dns: name does not exist") == 0) return -1; } return 0; }
/* notify a slave that an area has changed. */ static void send_notify(char *slave, RR *soa, Request *req) { int i, len, n, reqno, status, fd; char *err; uchar ibuf[Maxudp+Udphdrsize], obuf[Maxudp+Udphdrsize]; RR *rp; Udphdr *up = (Udphdr*)obuf; DNSmsg repmsg; /* create the request */ reqno = rand(); n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno); /* get an address */ if(strcmp(ipattr(slave), "ip") == 0) { if (parseip(up->raddr, slave) == -1) dnslog("bad address %s to notify", slave); } else { rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status); if(rp == nil) rp = dnresolve(slave, Cin, Taaaa, req, nil, 0, 1, 1, &status); if(rp == nil) return; parseip(up->raddr, rp->ip->name); rrfreelist(rp); /* was rrfree */ } fd = udpport(nil); if(fd < 0) return; /* send 3 times or until we get anything back */ n += Udphdrsize; for(i = 0; i < 3; i++, freeanswers(&repmsg)){ dnslog("sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name); memset(&repmsg, 0, sizeof repmsg); if(write(fd, obuf, n) != n) break; alarm(2*1000); len = read(fd, ibuf, sizeof ibuf); alarm(0); if(len <= Udphdrsize) continue; err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg, nil); if(err != nil) { free(err); continue; } if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify) break; } if (i < 3) freeanswers(&repmsg); close(fd); }
/* 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; }
/* * 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; }
/* * get the system name */ static void ipid(void) { uint8_t addr[6]; struct ndbtuple *t, *tt; char *p, *attr; struct ndbs s; int f; char buf[Maxpath]; /* use environment, ether addr, or ipaddr to get system name */ if (mysysname == 0) { /* * environment has priority. * * on the sgi power the default system name * is the ip address. ignore that. * */ p = getenv("sysname"); if (p && *p) { attr = ipattr(p); if (strcmp(attr, "ip") != 0) mysysname = strdup(p); } /* * the /net/ndb contains what the network * figured out from DHCP. use that name if * there is one. */ if (mysysname == 0 && netdb != NULL) { ndbreopen(netdb); for (tt = t = ndbparse(netdb); t != NULL; t = t->entry) { if (strcmp(t->attr, "sys") == 0) { mysysname = strdup(t->val); break; } } ndbfree(tt); } /* next network database, ip address, and ether address to find * a name */ if (mysysname == 0) { t = NULL; if (isvalidip(ipa)) free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t)); if (t == NULL) { for (f = 0; f < 3; f++) { snprintf(buf, sizeof(buf), "%s/ether%d", mntpt, f); if (myetheraddr(addr, buf) < 0) continue; snprintf(eaddr, sizeof(eaddr), "%E", addr); free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t)); if (t != NULL) break; } } for (tt = t; tt != NULL; tt = tt->entry) { if (strcmp(tt->attr, "sys") == 0) { mysysname = strdup(tt->val); break; } } ndbfree(t); } /* nothing else worked, use the ip address */ if (mysysname == 0 && isvalidip(ipa)) mysysname = strdup(ipaddr); /* set /dev/sysname if we now know it */ if (mysysname) { f = open("/dev/sysname", O_RDWR); if (f >= 0) { write(f, mysysname, strlen(mysysname)); close(f); } } } }
static char *ipinfoquery(struct mfile *mf, char **list, int n) { int i, nresolve; int resolve[Maxattr]; struct ndbtuple *t, *nt, **l; char *attr, *val; /* skip 'ipinfo' */ list++; n--; if (n < 1) return "bad query"; /* get search attribute=value, or assume ip=myipaddr */ attr = *list; val = strchr(attr, '='); if (val != NULL) { *val++ = 0; list++; n--; } else { attr = "ip"; val = ipaddr; } if (n < 1) return "bad query"; /* * don't let ndbipinfo resolve the addresses, we're * better at it. */ nresolve = 0; for (i = 0; i < n; i++) if (*list[i] == '@') { /* @attr=val ? */ list[i]++; resolve[i] = 1; /* we'll resolve it */ nresolve++; } else resolve[i] = 0; t = ndbipinfo(db, attr, val, list, n); if (t == NULL) return "no match"; if (nresolve != 0) { for (l = &t; *l != NULL;) { nt = *l; /* already an address? */ if (strcmp(ipattr(nt->val), "ip") == 0) { l = &(*l)->entry; continue; } /* user wants it resolved? */ for (i = 0; i < n; i++) if (strcmp(list[i], nt->attr) == 0) break; if (i >= n || resolve[i] == 0) { l = &(*l)->entry; continue; } /* resolve address and replace entry */ *l = ipresolve(nt->attr, nt->val); while (*l != NULL) l = &(*l)->entry; *l = nt->entry; nt->entry = NULL; ndbfree(nt); } } /* make it all one line */ for (nt = t; nt != NULL; nt = nt->entry) { if (nt->entry == NULL) nt->line = t; else nt->line = nt->entry; } qreply(mf, t); return NULL; }
/* * 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; }