]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/ndb/cs.c
merge
[plan9front.git] / sys / src / cmd / ndb / cs.c
index 33cbe8e8766f555c1ae466c3bcda0f24200019af..3fc9d0b3e6c6f70e19ce9a7ee5a7b054252823ac 100644 (file)
@@ -80,8 +80,7 @@ Job   *joblist;
 Mlist  *mlist;
 int    mfd[2];
 int    debug;
-int    paranoia;
-int    ipv6lookups = 1;
+
 jmp_buf        masterjmp;      /* return through here after a slave process has been created */
 int    *isslave;       /* *isslave non-zero means this is a slave process */
 long   active;         /* number of active slaves */
@@ -113,7 +112,6 @@ char        *genquery(Mfile*, char*);
 char*  ipinfoquery(Mfile*, char**, int);
 int    needproto(Network*, Ndbtuple*);
 int    lookup(Mfile*);
-Ndbtuple*      reorder(Ndbtuple*, Ndbtuple*);
 void   ipid(void);
 void   readipinterfaces(void);
 void*  emalloc(int);
@@ -127,7 +125,6 @@ QLock       dblock;         /* mutex on database operations */
 QLock  netlock;        /* mutex for netinit() */
 
 char   *logfile = "cs";
-char   *paranoiafile = "cs.paranoia";
 
 char   mntpt[Maxpath];
 char   netndb[Maxpath];
@@ -139,45 +136,52 @@ Ndbtuple* iplookup(Network*, char*, char*);
 char*          iptrans(Ndbtuple*, Network*, char*, char*, int);
 Ndbtuple*      telcolookup(Network*, char*, char*);
 char*          telcotrans(Ndbtuple*, Network*, char*, char*, int);
+
 Ndbtuple*      dnsiplookup(char*, Ndbs*, int);
+Ndbtuple*      myipinfo(Ndb *db, char **list, int n);
 
 struct Network
 {
        char            *net;
        Ndbtuple        *(*lookup)(Network*, char*, char*);
        char            *(*trans)(Ndbtuple*, Network*, char*, char*, int);
-       int             considered;             /* flag: ignored for "net!"? */
-       int             fasttimeouthack;        /* flag. was for IL */
+
+       char            considered;             /* flag: ignored for "net!"? */
+       char            fasttimeout;            /* flag. was for IL */
+       char            ipvers;                 /* flag: V4, V6 */
+
        Network         *next;
 };
 
 enum {
        Ntcp = 1,
+
+       V4 = 1,
+       V6 = 2,
 };
 
 /*
  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed).
  */
 Network network[] = {
-       { "il",         iplookup,       iptrans,        0, 1, },
-       { "tcp",        iplookup,       iptrans,        0, 0, },
-       { "il",         iplookup,       iptrans,        0, 0, },
-       { "udp",        iplookup,       iptrans,        1, 0, },
-       { "icmp",       iplookup,       iptrans,        1, 0, },
-       { "icmpv6",     iplookup,       iptrans,        1, 0, },
-       { "rudp",       iplookup,       iptrans,        1, 0, },
-       { "ssh",        iplookup,       iptrans,        1, 0, },
-       { "telco",      telcolookup,    telcotrans,     1, 0, },
+       { "il",         iplookup,       iptrans,        0, 1, V4,       },
+       { "tcp",        iplookup,       iptrans,        0, 0, V4|V6,    },
+       { "il",         iplookup,       iptrans,        0, 0, V4,       },
+       { "udp",        iplookup,       iptrans,        1, 0, V4|V6,    },
+       { "icmp",       iplookup,       iptrans,        1, 0, V4,       },
+       { "icmpv6",     iplookup,       iptrans,        1, 0, V6,       },
+       { "rudp",       iplookup,       iptrans,        1, 0, V4,       },
+       { "ssh",        iplookup,       iptrans,        1, 0, V4|V6,    },
+       { "telco",      telcolookup,    telcotrans,     1, 0, 0,        },
        { 0 },
 };
 
 QLock ipifclock;
 Ipifc *ipifcs;
+int confipvers;
+int lookipvers = V4|V6;
 
-char   eaddr[16];              /* ascii ethernet address */
-char   ipaddr[64];             /* ascii internet address */
-uchar  ipa[IPaddrlen];         /* binary internet address */
-char   *mysysname;
+char *mysysname;
 
 Network *netlist;              /* networks ordered by preference */
 Network *last;
@@ -192,7 +196,7 @@ nstrcpy(char *to, char *from, int len)
 void
 usage(void)
 {
-       fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0);
+       fprint(2, "usage: %s [-46dn] [-f ndb-file] [-x netmtpt]\n", argv0);
        exits("usage");
 }
 
@@ -232,7 +236,10 @@ main(int argc, char *argv[])
        ext[0] = 0;
        ARGBEGIN{
        case '4':
-               ipv6lookups = 0;
+               lookipvers = V4;
+               break;
+       case '6':
+               lookipvers = V6;
                break;
        case 'd':
                debug = 1;
@@ -796,20 +803,20 @@ rwrite(Job *job, Mfile *mf)
        }
 
        /*
-        *  toggle ipv6 lookups
+        *  toggle ipv4 lookups
         */
-       if(strncmp(job->request.data, "ipv6", 4)==0){
-               ipv6lookups ^= 1;
-               syslog(1, logfile, "ipv6lookups %d", ipv6lookups);
+       if(strncmp(job->request.data, "ipv4", 4)==0){
+               lookipvers ^= V4;
+               syslog(1, logfile, "ipv4lookups %d", (lookipvers & V4) != 0);
                goto send;
        }
 
        /*
-        *  toggle debugging
+        *  toggle ipv6 lookups
         */
-       if(strncmp(job->request.data, "paranoia", 8)==0){
-               paranoia ^= 1;
-               syslog(1, logfile, "paranoia %d", paranoia);
+       if(strncmp(job->request.data, "ipv6", 4)==0){
+               lookipvers ^= V6;
+               syslog(1, logfile, "ipv6lookups %d", (lookipvers & V6) != 0);
                goto send;
        }
 
@@ -852,8 +859,6 @@ query:
 
        if(debug)
                syslog(0, logfile, "write %s", job->request.data);
-       if(paranoia)
-               syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
        /*
         *  break up name
         */
@@ -979,33 +984,26 @@ error(char *s)
        _exits(0);
 }
 
-static int
-isvalidip(uchar *ip)
-{
-       return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
-}
-
-static uchar loopbacknet[IPaddrlen] = {
-       0, 0, 0, 0,
-       0, 0, 0, 0,
-       0, 0, 0xff, 0xff,
-       127, 0, 0, 0
-};
-static uchar loopbackmask[IPaddrlen] = {
-       0xff, 0xff, 0xff, 0xff,
-       0xff, 0xff, 0xff, 0xff,
-       0xff, 0xff, 0xff, 0xff,
-       0xff, 0, 0, 0
-};
-
 void
 readipinterfaces(void)
 {
-       if(myipaddr(ipa, mntpt) != 0)
-               ipmove(ipa, IPnoaddr);
-       sprint(ipaddr, "%I", ipa);
-       if (debug)
-               syslog(0, logfile, "ipaddr is %s", ipaddr);
+       Ipifc *ifc;
+       Iplifc *lifc;
+       int v;
+
+       v = 0;
+       qlock(&ipifclock);
+       ipifcs = readipifc(mntpt, ipifcs, -1);
+       for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
+               for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+                       if(isv4(lifc->ip))
+                               v |= V4;
+                       else
+                               v |= V6;
+               }
+       }
+       qunlock(&ipifclock);
+       confipvers = v;
 }
 
 /*
@@ -1014,94 +1012,86 @@ readipinterfaces(void)
 void
 ipid(void)
 {
+       char eaddr[16], buf[Maxpath];
        uchar addr[6];
        Ndbtuple *t, *tt;
        char *p, *attr;
        Ndbs s;
        int f, n;
        Dir *d;
-       char buf[Maxpath];
 
-       /* use environment, ether addr, or ipaddr to get system name */
-       if(mysysname == nil){
-               /*
-                *  environment has priority.
-                *
-                *  on the sgi power the default system name
-                *  is the ip address.  ignore that.
-                *
-                */
-               p = getenv("sysname");
-               if(p != nil && *p){
-                       attr = ipattr(p);
-                       if(strcmp(attr, "ip") != 0)
-                               mysysname = estrdup(p);
-               }
+       if(mysysname != nil)
+               return;
 
-               /*
-                *  the /net/ndb contains what the network
-                *  figured out from DHCP.  use that name if
-                *  there is one.
-                */
-               if(mysysname == nil && netdb != nil){
-                       ndbreopen(netdb);
-                       for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
-                               if(strcmp(t->attr, "sys") == 0){
-                                       mysysname = estrdup(t->val);
-                                       break;
-                               }
-                       }
-                       ndbfree(tt);
+       /*
+        *  environment has priority.
+        *
+        *  on the sgi power the default system name
+        *  is the ip address.  ignore that.
+        *
+        */
+       p = getenv("sysname");
+       if(p != nil && *p != 0){
+               attr = ipattr(p);
+               if(strcmp(attr, "ip") != 0) {
+                       mysysname = p;
+                       goto setsys;
                }
+               free(p);
+       }
 
-               /* next network database, ip address, and ether address to find a name */
-               if(mysysname == nil){
-                       t = nil;
-                       if(isvalidip(ipa))
-                               free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
-                       if(t == nil){
-                               n = 0;
-                               d = nil;
-                               f = open(mntpt, OREAD);
-                               if(f >= 0){
-                                       n = dirreadall(f, &d);
-                                       close(f);
-                               }
-                               for(f = 0; f < n; f++){
-                                       if((d[f].mode & DMDIR) == 0 || strncmp(d[f].name, "ether", 5) != 0)
-                                               continue;
-                                       snprint(buf, sizeof buf, "%s/%s", mntpt, d[f].name);
-                                       if(myetheraddr(addr, buf) >= 0){
-                                               snprint(eaddr, sizeof(eaddr), "%E", addr);
-                                               free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
-                                               if(t != nil)
-                                                       break;
-                                       }
-                               }
+       /* try configured interfaces */
+       attr = "sys";
+       t = s.t = myipinfo(db, &attr, 1);
+       if(t != nil)
+               goto found;
+
+       /* try ethernet interfaces */
+       n = 0;
+       d = nil;
+       f = open(mntpt, OREAD);
+       if(f >= 0){
+               n = dirreadall(f, &d);
+               close(f);
+       }
+       for(f = 0; f < n; f++){
+               if((d[f].mode & DMDIR) == 0 || strncmp(d[f].name, "ether", 5) != 0)
+                       continue;
+               snprint(buf, sizeof buf, "%s/%s", mntpt, d[f].name);
+               if(myetheraddr(addr, buf) >= 0){
+                       snprint(eaddr, sizeof(eaddr), "%E", addr);
+                       free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
+                       if(t != nil){
                                free(d);
+                               goto found;
                        }
-                       for(tt = t; tt != nil; tt = tt->entry){
-                               if(strcmp(tt->attr, "sys") == 0){
-                                       mysysname = estrdup(tt->val);
-                                       break;
-                               }
-                       }
-                       ndbfree(t);
                }
+       }
+       free(d);
 
-               /* nothing else worked, use the ip address */
-               if(mysysname == nil && isvalidip(ipa))
-                       mysysname = estrdup(ipaddr);
+       /* nothing else worked, use ip address */
+       attr = "ip";
+       t = s.t = myipinfo(db, &attr, 1);
+       if(t == nil)
+               return;
+       
+found:
+       /* found in database */
+       if((tt = ndbfindattr(t, s.t, "sys")) != nil)
+               mysysname = estrdup(tt->val);
+       else if((tt = ndbfindattr(t, s.t, "ip")) != nil)
+               mysysname = estrdup(tt->val);
+       ndbfree(t);
 
+       if(mysysname == nil)
+               return;
 
-               /* set /dev/sysname if we now know it */
-               if(mysysname != nil){
-                       f = open("/dev/sysname", OWRITE);
-                       if(f >= 0){
-                               write(f, mysysname, strlen(mysysname));
-                               close(f);
-                       }
-               }
+setsys:
+       /* set /dev/sysname if we now know it */
+       f = open("/dev/sysname", OWRITE);
+       if(f >= 0){
+               write(f, mysysname, strlen(mysysname));
+               close(f);
        }
 }
 
@@ -1114,15 +1104,10 @@ netinit(int background)
 {
        char clone[Maxpath];
        Network *np;
-       static int working;
 
        if(background){
-               switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
-               case 0:
-                       break;
-               default:
+               if(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT) != 0)
                        return;
-               }
                qlock(&netlock);
        }
 
@@ -1142,15 +1127,14 @@ netinit(int background)
                np->considered = 1;
        }
 
-       /* find out what our ip address is */
+       /* find out what our ip addresses are */
        readipinterfaces();
 
        /* set the system name if we need to, these days ip is all we have */
        ipid();
 
        if(debug)
-               syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I",
-                       mysysname?mysysname:"???", eaddr, ipaddr, ipa);
+               syslog(0, logfile, "mysysname %s", mysysname?mysysname:"???");
 
        if(background){
                qunlock(&netlock);
@@ -1206,8 +1190,7 @@ lookup(Mfile *mf)
        char *cp;
        Ndbtuple *nt, *t;
        char reply[Maxreply];
-       int i, rv;
-       int hack;
+       int i, rv, fasttimeout;
 
        /* open up the standard db files */
        if(db == nil)
@@ -1227,9 +1210,9 @@ lookup(Mfile *mf)
                        nt = (*np->lookup)(np, mf->host, mf->serv);
                        if(nt == nil)
                                continue;
-                       hack = np->fasttimeouthack && !lookforproto(nt, np->net);
+                       fasttimeout = np->fasttimeout && !lookforproto(nt, np->net);
                        for(t = nt; mf->nreply < Nreply && t != nil; t = t->entry){
-                               cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
+                               cp = (*np->trans)(t, np, mf->serv, mf->rem, fasttimeout);
                                if(cp != nil){
                                        /* avoid duplicates */
                                        for(i = 0; i < mf->nreply; i++)
@@ -1260,7 +1243,7 @@ lookup(Mfile *mf)
         *  look for a specific network
         */
        for(np = network; np->net != nil; np++){
-               if(np->fasttimeouthack)
+               if(np->fasttimeout)
                        continue;
                if(strcmp(np->net, mf->net) == 0)
                        break;
@@ -1310,7 +1293,6 @@ ipserv(Network *np, char *name, char *buf, int blen)
        char *p;
        int alpha = 0;
        int restr = 0;
-       char port[10];
        Ndbtuple *t, *nt;
        Ndbs s;
 
@@ -1321,7 +1303,6 @@ ipserv(Network *np, char *name, char *buf, int blen)
        }
 
        /*  see if it's numeric or symbolic */
-       port[0] = 0;
        for(p = name; *p; p++){
                if(isdigit(*p))
                        {}
@@ -1358,122 +1339,147 @@ ipserv(Network *np, char *name, char *buf, int blen)
        return buf;
 }
 
-/*
- *  lookup an ip attribute
- */
-int
-ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
+Ndbtuple*
+myipinfo(Ndb *db, char **list, int n)
 {
-
        Ndbtuple *t, *nt;
-       char *alist[2];
+       char ip[64];
+       Ipifc *ifc;
+       Iplifc *lifc;
 
-       alist[0] = attr;
-       t = ndbipinfo(db, "ip", ipa, alist, 1);
-       if(t == nil)
-               return 0;
-       for(nt = t; nt != nil; nt = nt->entry){
-               if(strcmp(nt->attr, attr) == 0){
-                       nstrcpy(val, nt->val, vlen);
-                       ndbfree(t);
-                       return 1;
+       t = nil;
+       qlock(&ipifclock);
+       for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
+               for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+                       snprint(ip, sizeof(ip), "%I", lifc->ip);
+                       nt = ndbipinfo(db, "ip", ip, list, n);
+                       t = ndbconcatenate(t, nt);
                }
        }
+       qunlock(&ipifclock);
 
-       /* we shouldn't get here */
-       ndbfree(t);
-       return 0;
+       return t;
 }
 
 /*
- *  lookup (and translate) an ip destination
+ * reorder according to our interfaces
  */
-Ndbtuple*
-iplookup(Network *np, char *host, char *serv)
+static Ndbtuple*
+ipreorder(Ndbtuple *t)
 {
-       char *attr, *dnsname;
-       Ndbtuple *t, *nt;
-       Ndbs s;
-       char ts[Maxservice];
-       char dollar[Maxhost];
+       Ndbtuple *nt;
        uchar ip[IPaddrlen];
        uchar net[IPaddrlen];
        uchar tnet[IPaddrlen];
        Ipifc *ifc;
        Iplifc *lifc;
-       int v6;
 
-       /*
-        *  start with the service since it's the most likely to fail
-        *  and costs the least
-        */
-       werrstr("can't translate address");
-       if(serv == nil || ipserv(np, serv, ts, sizeof ts) == nil){
-               werrstr("can't translate service");
+       if(t == nil)
                return nil;
-       }
 
-       /* for dial strings with no host */
-       if(strcmp(host, "*") == 0)
-               return ndbnew("ip", "*");
+       qlock(&ipifclock);
+       for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
+               for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+                       maskip(lifc->ip, lifc->mask, net);
+                       for(nt = t; nt != nil; nt = nt->entry){
+                               if(strcmp(nt->attr, "ip") != 0)
+                                       continue;
+                               if(parseip(ip, nt->val) == -1)
+                                       continue;
+                               maskip(ip, lifc->mask, tnet);
+                               if(memcmp(net, tnet, IPaddrlen) == 0){
+                                       qunlock(&ipifclock);
+                                       return ndbreorder(t, nt);
+                               }
+                       }
+               }
+       }
+       qunlock(&ipifclock);
 
-       /*
-        *  hack till we go v6 :: = 0.0.0.0
-        */
-       if(strcmp("::", host) == 0)
-               return ndbnew("ip", "*");
+       return t;
+}
 
+static Ndbtuple*
+ndbline(Ndbtuple *t)
+{
+       Ndbtuple *nt;
 
-       /*
-        *  '$' 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;
+       for(nt = t; nt != nil; nt = nt->entry){
+               if(nt->entry == nil)
+                       nt->line = t;
+               else
+                       nt->line = nt->entry;
        }
+       return t;
+}
+
+/*
+ *  lookup an ip destination
+ */
+static Ndbtuple*
+iplookuphost(Network *np, char *host)
+{
+       char *attr, *dnsname;
+       Ndbtuple *t, *nt;
+       Ndbs s;
 
        /*
         *  turn '[ip address]' into just 'ip address'
         */
        if(*host == '['){
-               char *x;
+               char tmp[Maxhost], *x;
 
-               if(host != dollar){
-                       nstrcpy(dollar, host, sizeof dollar);
-                       host = dollar;
-               }
-               if(x = strchr(++host, ']'))
+               nstrcpy(tmp, host, sizeof tmp);
+               host = tmp;
+               if((x = strchr(++host, ']')) != nil)
                        *x = 0;
        }
 
+       /* for dial strings with no host */
+       if(strcmp(host, "*") == 0)
+               return ndbline(ndbnew("ip", "*"));
+
+       /*
+        *  hack till we go v6 :: = 0.0.0.0
+        */
+       if(strcmp("::", host) == 0)
+               return ndbline(ndbnew("ip", "*"));
+
        /*
         *  just accept addresses
         */
        attr = ipattr(host);
        if(strcmp(attr, "ip") == 0)
-               return ndbnew("ip", host);
+               return ndbline(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");
-       v6 = strcmp(np->net, "il") != 0;
+       t = nil;
        if(strcmp(attr, "dom") == 0)
-               t = dnsiplookup(host, &s, v6);
-       if(t == nil)
-               free(ndbgetvalue(db, &s, attr, host, "ip", &t));
+               t = dnsiplookup(host, &s, np->ipvers);
        if(t == nil){
-               dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
-               if(dnsname){
-                       t = dnsiplookup(dnsname, &s, v6);
-                       free(dnsname);
+               for(nt = ndbsearch(db, &s, attr, host); nt != nil; nt = ndbsnext(&s, attr, host)){
+                       if(ndbfindattr(nt, s.t, "ip") == nil){
+                               ndbfree(nt);
+                               continue;
+                       }
+                       t = ndbconcatenate(t, ndbreorder(nt, s.t));
                }
+               s.t = t;
+       }
+       if(t == nil){
+               if(strcmp(attr, "dom") != 0){
+                       dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
+                       if(dnsname != nil){
+                               t = dnsiplookup(dnsname, &s, np->ipvers);
+                               free(dnsname);
+                       }
+               }
+               if(t == nil)
+                       t = dnsiplookup(host, &s, np->ipvers);
        }
-       if(t == nil)
-               t = dnsiplookup(host, &s, v6);
        if(t == nil)
                return nil;
 
@@ -1481,49 +1487,56 @@ iplookup(Network *np, char *host, char *serv)
         *  reorder the tuple to have the matched line first and
         *  save that in the request structure.
         */
-       t = reorder(t, s.t);
+       return ndbreorder(t, s.t);
+}
+
+
+Ndbtuple*
+iplookup(Network *np, char *host, char *serv)
+{
+       Ndbtuple *l, *t, *nt;
+       char ts[Maxservice], *attr;
 
        /*
-        * reorder according to our interfaces
+        *  start with the service since it's the most likely to fail
+        *  and costs the least
         */
-       qlock(&ipifclock);
-       for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
-               for(lifc = ifc->lifc; lifc != nil; 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);
-                                       qunlock(&ipifclock);
-                                       return t;
-                               }
-                       }
-               }
+       if(serv == nil || ipserv(np, serv, ts, sizeof ts) == nil){
+               werrstr("can't translate service");
+               return nil;
        }
-       qunlock(&ipifclock);
 
-       return t;
-}
+       /*
+        *  '$' means the rest of the name is an attribute that we
+        *  need to search for
+        */
+       werrstr("can't translate address");
+       if(*host == '$'){
+               t = nil;
+               attr = host+1;
+               l = myipinfo(db, &attr, 1);
+               for(nt = l; nt != nil; nt = nt->entry){
+                       if(strcmp(nt->attr, attr) == 0)
+                               t = ndbconcatenate(t, iplookuphost(np, nt->val));
+               }
+               ndbfree(l);
+       } else
+               t = iplookuphost(np, host);
 
-static int
-isv4str(char *s)
-{
-       uchar ip[IPaddrlen];
-       return parseip(ip, s) != -1 && isv4(ip);
+       return ipreorder(t);
 }
 
+
 /*
  *  translate an ip address
  */
 char*
-iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
+iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int fasttimeout)
 {
        char ts[Maxservice];
        char reply[Maxreply];
        char x[Maxservice];
+       uchar ip[IPaddrlen];
 
        if(strcmp(t->attr, "ip") != 0)
                return nil;
@@ -1532,6 +1545,7 @@ iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
                werrstr("can't translate service");
                return nil;
        }
+
        if(rem != nil)
                snprint(x, sizeof(x), "!%s", rem);
        else
@@ -1541,12 +1555,12 @@ iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
                snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
                        mntpt, np->net, ts, x);
        else {
-               /* il only supports ipv4 addresses */
-               if(strcmp(np->net, "il") == 0 && !isv4str(t->val))
+               if(parseip(ip, t->val) == -1)
                        return nil;
-
-               snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
-                       mntpt, np->net, t->val, ts, x, hack? "!fasttimeout": "");
+               if((np->ipvers & confipvers & (isv4(ip) ? V4 : V6)) == 0)
+                       return nil;
+               snprint(reply, sizeof(reply), "%s/%s/clone %I!%s%s%s",
+                       mntpt, np->net, ip, ts, x, fasttimeout? "!fasttimeout": "");
        }
 
        return estrdup(reply);
@@ -1566,9 +1580,9 @@ telcolookup(Network *np, char *host, char *serv)
        werrstr("can't translate address");
        free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
        if(t == nil)
-               return ndbnew("telco", host);
+               return ndbline(ndbnew("telco", host));
 
-       return reorder(t, s.t);
+       return ndbreorder(t, s.t);
 }
 
 /*
@@ -1596,34 +1610,6 @@ telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
        return estrdup(reply);
 }
 
-/*
- *  reorder the tuple to put x's line first in the entry
- */
-Ndbtuple*
-reorder(Ndbtuple *t, Ndbtuple *x)
-{
-       Ndbtuple *nt;
-       Ndbtuple *line;
-
-       /* find start of this entry's line */
-       for(line = x; line->entry == line->line; line = line->line)
-               ;
-       line = line->line;
-       if(line == t)
-               return t;       /* already the first line */
-
-       /* remove this line and everything after it from the entry */
-       for(nt = t; nt->entry != line; nt = nt->entry)
-               ;
-       nt->entry = nil;
-
-       /* make that the start of the entry */
-       for(nt = line; nt->entry != nil; nt = nt->entry)
-               ;
-       nt->entry = t;
-       return line;
-}
-
 /*
  *  create a slave process to handle a request to avoid one request blocking
  *  another.  parent returns to job loop.
@@ -1653,6 +1639,43 @@ slave(char *host)
 
 }
 
+static int
+mountdns(void)
+{
+       static QLock mountlock;
+       static int mounted;
+       char buf[128], *p;
+       int fd;
+
+       if(mounted)
+               return 0;
+
+       qlock(&mountlock);
+       snprint(buf, sizeof(buf), "%s/dns", mntpt);
+       if(access(buf, AEXIST) == 0)
+               goto done;
+       if(strcmp(mntpt, "/net") == 0)
+               snprint(buf, sizeof(buf), "/srv/dns");
+       else {
+               snprint(buf, sizeof(buf), "/srv/dns%s", mntpt);
+               while((p = strchr(buf+8, '/')) != nil)
+                       *p = '_';
+       }
+       if((fd = open(buf, ORDWR)) < 0){
+err:
+               qunlock(&mountlock);
+               return -1;      
+       }
+       if(mount(fd, -1, mntpt, MAFTER, "") < 0){
+               close(fd);
+               goto err;
+       }
+done:
+       mounted = 1;
+       qunlock(&mountlock);
+       return 0;
+}
+
 static Ndbtuple*
 dnsip6lookup(char *mntpt, char *buf, Ndbtuple *t)
 {
@@ -1667,25 +1690,24 @@ dnsip6lookup(char *mntpt, char *buf, Ndbtuple *t)
                if (strcmp(tt->attr, "ipv6") == 0)
                        strcpy(tt->attr, "ip");
 
-       if (t == nil)
-               return t6;
-
        /* append t6 list to t list */
-       for (tt = t; tt->entry != nil; tt = tt->entry)
-               ;
-       tt->entry = t6;
-       return t;
+       return ndbconcatenate(t, t6);
 }
 
 /*
  *  call the dns process and have it try to translate a name
  */
 Ndbtuple*
-dnsiplookup(char *host, Ndbs *s, int v6)
+dnsiplookup(char *host, Ndbs *s, int ipvers)
 {
        char buf[Maxreply];
        Ndbtuple *t;
 
+       ipvers &= confipvers & lookipvers;
+       if(ipvers == 0){
+               werrstr("no ip address");
+               return nil;
+       }
        qunlock(&dblock);
        slave(host);
        if(*isslave == 0){
@@ -1694,12 +1716,18 @@ dnsiplookup(char *host, Ndbs *s, int v6)
                return nil;
        }
 
+       if(mountdns() < 0){
+               qlock(&dblock);
+               return nil;
+       }
+
        if(strcmp(ipattr(host), "ip") == 0)
                t = dnsquery(mntpt, host, "ptr");
        else {
-               t = dnsquery(mntpt, host, "ip");
-               /* special case: query ipv6 (AAAA dns RR) too */
-               if (v6 && ipv6lookups)
+               t = nil;
+               if(ipvers & V4)
+                       t = dnsquery(mntpt, host, "ip");
+               if(ipvers & V6)
                        t = dnsip6lookup(mntpt, host, t);
        }
        s->t = t;
@@ -1805,7 +1833,7 @@ genquery(Mfile *mf, char *query)
 
        /* give dns a chance */
        if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
-               t = dnsiplookup(val[0], &s, 1);
+               t = dnsiplookup(val[0], &s, lookipvers);
                if(t != nil){
                        if(qmatch(t, attr, val, n)){
                                qreply(mf, t);
@@ -1857,11 +1885,34 @@ ipresolve(char *attr, char *host)
        return t;
 }
 
+/*
+ *  remove duplicates
+ */
+static Ndbtuple*
+ndbdedup(Ndbtuple *t)
+{
+       Ndbtuple *tt, *nt, **l;
+
+       for(nt = t; nt != nil; nt = nt->entry){
+               for(l = &nt->entry; (tt = *l) != nil;){
+                       if(strcmp(nt->attr, tt->attr) != 0
+                       || strcmp(nt->val, tt->val) != 0){
+                               l = &tt->entry;
+                               continue;
+                       }
+                       *l = tt->entry;
+                       tt->entry = nil;
+                       ndbfree(tt);
+               }
+       }
+       return t;
+}
+
 char*
 ipinfoquery(Mfile *mf, char **list, int n)
 {
        int i, nresolve;
-       int resolve[Maxattr];
+       uchar resolve[Maxattr];
        Ndbtuple *t, *nt, **l;
        char *attr, *val;
 
@@ -1871,20 +1922,20 @@ ipinfoquery(Mfile *mf, char **list, int n)
        if(n < 1)
                return "bad query";
 
-       /* get search attribute=value, or assume ip=myipaddr */
+       /* get search attribute=value, or assume myip */
        attr = *list;
        if((val = strchr(attr, '=')) != nil){
                *val++ = 0;
                list++;
                n--;
        }else{
-               attr = "ip";
-               val = ipaddr;
+               attr = nil;
+               val = nil;
        }
-
        if(n < 1)
                return "bad query";
 
+
        /*
         *  don't let ndbipinfo resolve the addresses, we're
         *  better at it.
@@ -1898,11 +1949,16 @@ ipinfoquery(Mfile *mf, char **list, int n)
                } else
                        resolve[i] = 0;
 
-       t = ndbipinfo(db, attr, val, list, n);
+       if(attr == nil)
+               t = myipinfo(db, list, n);
+       else
+               t = ndbipinfo(db, attr, val, list, n);
+
        if(t == nil)
                return "no match";
 
        if(nresolve != 0){
+               t = ndbdedup(t);
                for(l = &t; *l != nil;){
                        nt = *l;
 
@@ -1931,14 +1987,10 @@ ipinfoquery(Mfile *mf, char **list, int n)
                        ndbfree(nt);
                }
        }
+       t = ndbdedup(t);
 
        /* make it all one line */
-       for(nt = t; nt != nil; nt = nt->entry){
-               if(nt->entry == nil)
-                       nt->line = t;
-               else
-                       nt->line = nt->entry;
-       }
+       t = ndbline(t);
 
        qreply(mf, t);