]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/ndb/dblookup.c
ndb/dns: do recursive lookup for dnsslave=
[plan9front.git] / sys / src / cmd / ndb / dblookup.c
index 5260f47af6f6d464142c0cdcbeb748feecf6ecc4..ec3f94d1cb980073fb2db6cba8c170c89ac8b9ac 100644 (file)
@@ -20,8 +20,11 @@ enum {
        Ptrttl = 2*Min,
 };
 
-static Ndb *db;
-static Lock    dblock;
+static Ndb     *db;
+static QLock   dblock;
+
+static Ipifc   *ipifcs;
+static QLock   ipifclock;
 
 static RR*     addrrr(Ndbtuple*, Ndbtuple*);
 static RR*     cnamerr(Ndbtuple*, Ndbtuple*);
@@ -67,7 +70,7 @@ opendatabase(void)
        char netdbnm[256];
        Ndb *xdb, *netdb;
 
-       if (db)
+       if(db != nil)
                return 0;
 
        xdb = ndbopen(dbfile);          /* /lib/ndb */
@@ -84,7 +87,7 @@ opendatabase(void)
                netdb->nohash = 1;
 
        db = ndbcat(netdb, xdb);        /* both */
-       return db? 0: -1;
+       return db!=nil ? 0: -1;
 }
 
 /*
@@ -103,8 +106,7 @@ RR*
 dblookup(char *name, int class, int type, int auth, int ttl)
 {
        int err;
-       char *wild;
-       char buf[256];
+       char buf[Domlen], *wild;
        RR *rp, *tp;
        DN *dp, *ndp;
 
@@ -123,8 +125,8 @@ dblookup(char *name, int class, int type, int auth, int ttl)
                return rp;
        }
 
-       lock(&dblock);
-       dp = dnlookup(name, class, 1);
+       qlock(&dblock);
+       dp = idnlookup(name, class, 1);
 
        if(opendatabase() < 0)
                goto out;
@@ -142,7 +144,7 @@ dblookup(char *name, int class, int type, int auth, int ttl)
        /* walk the domain name trying the wildcard '*' at each position */
        for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
                snprint(buf, sizeof buf, "*%s", wild);
-               ndp = dnlookup(buf, class, 1);
+               ndp = idnlookup(buf, class, 1);
                if(ndp->rr)
                        err = 0;
                if(cfg.cachedb)
@@ -162,12 +164,12 @@ out:
                 * don't call it non-existent if it's not ours
                 * (unless we're a resolver).
                 */
-               if(err == Rname && (!inmyarea(name) || cfg.resolver))
+               if(err == Rname && (!inmyarea(dp->name) || cfg.resolver))
                        err = Rserver;
                dp->respcode = err;
        }
 
-       unlock(&dblock);
+       qunlock(&dblock);
        return rp;
 }
 
@@ -179,6 +181,18 @@ intval(Ndbtuple *entry, Ndbtuple *pair, char *attr, ulong def)
        return (t? strtoul(t->val, 0, 10): def);
 }
 
+static void
+mklowcase(char *cp)
+{
+       Rune r;
+
+       while(*cp != 0){
+               chartorune(&r, cp);
+               r = tolowerrune(r);
+               cp += runetochar(cp, &r);
+       }
+}
+
 /*
  *  lookup an RR in the network database
  */
@@ -236,7 +250,7 @@ dblookup1(char *name, int type, int auth, int ttl)
        case Tixfr:
                return doaxfr(db, name);
        default:
-//             dnslog("dnlookup1(%s) bad type", name);
+//             dnslog("dblookup1(%s) bad type", name);
                return nil;
        }
 
@@ -245,28 +259,52 @@ dblookup1(char *name, int type, int auth, int ttl)
         */
        t = nil;
        nstrcpy(dname, name, sizeof dname);
-       free(ndbgetvalue(db, &s, "dom", dname, attr, &t));
-       if(t == nil && strchr(dname, '.') == nil)
-               free(ndbgetvalue(db, &s, "sys", dname, attr, &t));
-       if(t == nil) {
-               char *cp;
-
-               /* try lower case */
-               for(cp = dname; *cp; cp++)
-                       if(isupper(*cp)) {
-                               for(; *cp; cp++)
-                                       *cp = tolower(*cp);
-                               free(ndbgetvalue(db, &s, "dom", dname, attr, &t));
-                               if(t == nil && strchr(dname, '.') == nil)
-                                       free(ndbgetvalue(db, &s, "sys", dname, attr, &t));
-                               break;
+       for(x=0; x<4; x++){
+               switch(x){
+               case 1: /* try unicode */
+                       if(idn2utf(name, dname, sizeof dname) < 0){
+                               nstrcpy(dname, name, sizeof dname);
+                               continue;
                        }
+                       if(strcmp(name, dname) == 0)
+                               continue;
+                       break;
+               case 3: /* try ascii (lower case) */
+                       if(utf2idn(name, dname, sizeof dname) < 0)
+                               continue;
+               case 2:
+                       mklowcase(dname);
+                       if(strcmp(name, dname) == 0)
+                               continue;
+                       break;
+               }
+               for(nt = ndbsearch(db, &s, "dom", dname); nt != nil; nt = ndbsnext(&s, "dom", dname)) {
+                       if(ndbfindattr(nt, s.t, attr) == nil) {
+                               ndbfree(nt);
+                               continue;
+                       }
+                       t = ndbconcatenate(t, ndbreorder(nt, s.t));
+               }
+               if(t == nil && strchr(dname, '.') == nil) {
+                       for(nt = ndbsearch(db, &s, "sys", dname); nt != nil; nt = ndbsnext(&s, "sys", dname)) {
+                               if(ndbfindattr(nt, s.t, attr) == nil) {
+                                       ndbfree(nt);
+                                       continue;
+                               }
+                               t = ndbconcatenate(t, ndbreorder(nt, s.t));
+                       }
+               }
+               s.t = t;
+               if(t != nil)
+                       break;
        }
+
        if(t == nil) {
-//             dnslog("dnlookup1(%s) name not found", name);
+//             dnslog("dblookup1(%s) name not found", name);
                return nil;
        }
 
+
        /* search whole entry for default domain name */
        for(nt = t; nt; nt = nt->entry)
                if(strcmp(nt->attr, "dom") == 0){
@@ -296,14 +334,13 @@ dblookup1(char *name, int type, int auth, int ttl)
                        nstrcpy(dname, nt->val, sizeof dname);
                        found = 1;
                }
-               if(strcmp(attr, nt->attr) == 0){
-                       rp = (*f)(t, nt);
+               if(strcmp(attr, nt->attr) == 0 && (rp = (*f)(t, nt)) != nil){
                        rp->auth = auth;
                        rp->db = 1;
                        if(ttl)
                                rp->ttl = ttl;
                        if(dp == nil)
-                               dp = dnlookup(dname, Cin, 1);
+                               dp = idnlookup(dname, Cin, 1);
                        rp->owner = dp;
                        *l = rp;
                        l = &rp->next;
@@ -316,21 +353,20 @@ dblookup1(char *name, int type, int auth, int ttl)
 
        /* search whole entry */
        for(nt = t; nt; nt = nt->entry)
-               if(nt->ptr == 0 && strcmp(attr, nt->attr) == 0){
-                       rp = (*f)(t, nt);
+               if(nt->ptr == 0 && strcmp(attr, nt->attr) == 0 && (rp = (*f)(t, nt)) != nil){
+                       rp->auth = auth;
                        rp->db = 1;
                        if(ttl)
                                rp->ttl = ttl;
-                       rp->auth = auth;
                        if(dp == nil)
-                               dp = dnlookup(dname, Cin, 1);
+                               dp = idnlookup(dname, Cin, 1);
                        rp->owner = dp;
                        *l = rp;
                        l = &rp->next;
                }
        ndbfree(t);
 
-//     dnslog("dnlookup1(%s) -> %#p", name, list);
+//     dnslog("dblookup1(%s) -> %#p", name, list);
        return list;
 }
 
@@ -338,26 +374,22 @@ dblookup1(char *name, int type, int auth, int ttl)
  *  make various types of resource records from a database entry
  */
 static RR*
-addrrr(Ndbtuple *entry, Ndbtuple *pair)
+addrrr(Ndbtuple*, Ndbtuple *pair)
 {
        RR *rp;
-       uchar addr[IPaddrlen];
+       uchar ip[IPaddrlen];
 
-       USED(entry);
-       parseip(addr, pair->val);
-       if(isv4(addr))
-               rp = rralloc(Ta);
-       else
-               rp = rralloc(Taaaa);
-       rp->ip = dnlookup(pair->val, Cin, 1);
+       if(parseip(ip, pair->val) == -1)
+               return nil;
+       rp = rralloc(isv4(ip) ? Ta : Taaaa);
+       rp->ip = ipalookup(ip, Cin, 1);
        return rp;
 }
 static RR*
-nullrr(Ndbtuple *entry, Ndbtuple *pair)
+nullrr(Ndbtuple*, Ndbtuple *pair)
 {
        RR *rp;
 
-       USED(entry);
        rp = rralloc(Tnull);
        rp->null->data = (uchar*)estrdup(pair->val);
        rp->null->dlen = strlen((char*)rp->null->data);
@@ -369,13 +401,12 @@ nullrr(Ndbtuple *entry, Ndbtuple *pair)
  *  <= 255 byte ones.
  */
 static RR*
-txtrr(Ndbtuple *entry, Ndbtuple *pair)
+txtrr(Ndbtuple*, Ndbtuple *pair)
 {
        RR *rp;
        Txt *t, **l;
        int i, len, sofar;
 
-       USED(entry);
        rp = rralloc(Ttxt);
        l = &rp->txt;
        rp->txt = nil;
@@ -400,13 +431,12 @@ txtrr(Ndbtuple *entry, Ndbtuple *pair)
        return rp;
 }
 static RR*
-cnamerr(Ndbtuple *entry, Ndbtuple *pair)
+cnamerr(Ndbtuple*, Ndbtuple *pair)
 {
        RR *rp;
 
-       USED(entry);
        rp = rralloc(Tcname);
-       rp->host = dnlookup(pair->val, Cin, 1);
+       rp->host = idnlookup(pair->val, Cin, 1);
        return rp;
 }
 static RR*
@@ -415,7 +445,7 @@ mxrr(Ndbtuple *entry, Ndbtuple *pair)
        RR *rp;
 
        rp = rralloc(Tmx);
-       rp->host = dnlookup(pair->val, Cin, 1);
+       rp->host = idnlookup(pair->val, Cin, 1);
        rp->pref = intval(entry, pair, "pref", 1);
        return rp;
 }
@@ -426,18 +456,17 @@ nsrr(Ndbtuple *entry, Ndbtuple *pair)
        Ndbtuple *t;
 
        rp = rralloc(Tns);
-       rp->host = dnlookup(pair->val, Cin, 1);
+       rp->host = idnlookup(pair->val, Cin, 1);
        t = look(entry, pair, "soa");
        if(t && t->val[0] == 0)
                rp->local = 1;
        return rp;
 }
 static RR*
-ptrrr(Ndbtuple *entry, Ndbtuple *pair)
+ptrrr(Ndbtuple*, Ndbtuple *pair)
 {
        RR *rp;
 
-       USED(entry);
        rp = rralloc(Tns);
        rp->ptr = dnlookup(pair->val, Cin, 1);
        return rp;
@@ -466,7 +495,7 @@ soarr(Ndbtuple *entry, Ndbtuple *pair)
        ns = look(entry, pair, "ns");
        if(ns == nil)
                ns = look(entry, pair, "dom");
-       rp->host = dnlookup(ns->val, Cin, 1);
+       rp->host = idnlookup(ns->val, Cin, 1);
 
        /* accept all of:
         *  mbox=person
@@ -481,15 +510,15 @@ soarr(Ndbtuple *entry, Ndbtuple *pair)
                        p = strchr(mb->val, '@');
                        if(p != nil)
                                *p = '.';
-                       rp->rmb = dnlookup(mb->val, Cin, 1);
+                       rp->rmb = idnlookup(mb->val, Cin, 1);
                } else {
                        snprint(mailbox, sizeof mailbox, "%s.%s",
                                mb->val, ns->val);
-                       rp->rmb = dnlookup(mailbox, Cin, 1);
+                       rp->rmb = idnlookup(mailbox, Cin, 1);
                }
        else {
                snprint(mailbox, sizeof mailbox, "postmaster.%s", ns->val);
-               rp->rmb = dnlookup(mailbox, Cin, 1);
+               rp->rmb = idnlookup(mailbox, Cin, 1);
        }
 
        /*
@@ -509,7 +538,7 @@ srvrr(Ndbtuple *entry, Ndbtuple *pair)
        RR *rp;
 
        rp = rralloc(Tsrv);
-       rp->host = dnlookup(pair->val, Cin, 1);
+       rp->host = idnlookup(pair->val, Cin, 1);
        rp->srv->pri = intval(entry, pair, "pri", 0);
        rp->srv->weight = intval(entry, pair, "weight", 0);
        /* TODO: translate service name to port # */
@@ -541,16 +570,6 @@ look(Ndbtuple *entry, Ndbtuple *line, char *attr)
        return 0;
 }
 
-static RR**
-linkrr(RR *rp, DN *dp, RR **l)
-{
-       rp->owner = dp;
-       rp->auth = 1;
-       rp->db = 1;
-       *l = rp;
-       return &rp->next;
-}
-
 /* these are answered specially by the tcp version */
 static RR*
 doaxfr(Ndb *db, char *name)
@@ -559,23 +578,6 @@ doaxfr(Ndb *db, char *name)
        return 0;
 }
 
-
-/*
- *  read the all the soa's from the database to determine area's.
- *  this is only used when we're not caching the database.
- */
-static void
-dbfile2area(Ndb *db)
-{
-       Ndbtuple *t;
-
-       if(debug)
-               dnslog("rereading %s", db->file);
-       Bseek(&db->b, 0, 0);
-       while(t = ndbparse(db))
-               ndbfree(t);
-}
-
 /*
  *  read the database into the cache
  */
@@ -624,7 +626,7 @@ dbtuple2cache(Ndbtuple *t)
 
        for(et = t; et; et = et->entry)
                if(strcmp(et->attr, "dom") == 0){
-                       dp = dnlookup(et->val, Cin, 1);
+                       dp = idnlookup(et->val, Cin, 1);
 
                        /* first same line */
                        for(nt = et->line; nt != et; nt = nt->line){
@@ -691,13 +693,16 @@ db2cache(int doit)
 
        refresh_areas(owned);
 
-       lock(&dblock);
-
+       qlock(&dblock);
        if(opendatabase() < 0){
-               unlock(&dblock);
+               qunlock(&dblock);
                return;
        }
 
+       qlock(&ipifclock);
+       ipifcs = readipifc(mntpt, ipifcs, -1);
+       qunlock(&ipifclock);
+
        /*
         *  file may be changing as we are reading it, so loop till
         *  mod times are consistent.
@@ -730,34 +735,33 @@ db2cache(int doit)
                /* reload straddle-server configuration */
                loaddomsrvs();
 
-               if(cfg.cachedb){
-                       /* mark all db records as timed out */
-                       dnagedb();
+               /* mark all db records as timed out */
+               dnagedb();
 
+               if(cfg.cachedb){
                        /* read in new entries */
                        for(ndb = db; ndb; ndb = ndb->next)
                                dbfile2cache(ndb);
+               }
 
-                       /* mark as authoritative anything in our domain */
-                       dnauthdb();
+               /*
+                * mark as authoritative anything in our domain,
+                * delete timed out db records
+                */
+               dnauthdb();
 
-                       /* remove old entries */
-                       dnageall(1);
-               } else
-                       /* read all the soa's to get database defaults */
-                       for(ndb = db; ndb; ndb = ndb->next)
-                               dbfile2area(ndb);
+               /* remove old entries */
+               dnageall(1);
 
                doit = 0;
                lastyoungest = youngest;
                createptrs();
        }
 
-       unlock(&dblock);
+       qunlock(&dblock);
 }
 
 extern char    mntpt[Maxpath];         /* net mountpoint */
-static uchar   ipaddr[IPaddrlen];      /* my ip address */
 
 /*
  *  get all my xxx
@@ -766,29 +770,32 @@ static uchar      ipaddr[IPaddrlen];      /* my ip address */
 Ndbtuple*
 lookupinfo(char *attr)
 {
-       char buf[64];
-       char *a[2];
-       Ndbtuple *t;
-
-       if(ipcmp(ipaddr, IPnoaddr) == 0)
-               if(myipaddr(ipaddr, mntpt) < 0)
-                       return nil;
-
-       snprint(buf, sizeof buf, "%I", ipaddr);
-       a[0] = attr;
+       Ndbtuple *t, *nt;
+       char ip[64];
+       Ipifc *ifc;
+       Iplifc *lifc;
 
-       lock(&dblock);
+       t = nil;
+       qlock(&dblock);
        if(opendatabase() < 0){
-               unlock(&dblock);
+               qunlock(&dblock);
                return nil;
        }
-       t = ndbipinfo(db, "ip", buf, a, 1);
-       unlock(&dblock);
-       return t;
-}
+       qlock(&ipifclock);
+       if(ipifcs == nil)
+               ipifcs = readipifc(mntpt, ipifcs, -1);
+       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, &attr, 1);
+                       t = ndbconcatenate(t, nt);
+               }
+       }
+       qunlock(&ipifclock);
+       qunlock(&dblock);
 
-char *localservers =     "local#dns#servers";
-char *localserverprefix = "local#dns#server";
+       return ndbdedup(t);
+}
 
 /*
  *  return non-zero if this is a bad delegation
@@ -825,75 +832,71 @@ baddelegation(RR *rp, RR *nsrp, uchar *addr)
 }
 
 int
-myaddr(char *addr)
+myip(uchar *ip)
 {
-       char *line, *sp;
-       char buf[64];
-       Biobuf *bp;
-
-       if(ipcmp(ipaddr, IPnoaddr) == 0)
-               if(myipaddr(ipaddr, mntpt) < 0)
-                       return -1;
-
-       snprint(buf, sizeof buf, "%I", ipaddr);
-       if (strcmp(addr, buf) == 0) {
-               dnslog("rejecting my ip %s as local dns server", addr);
-               return 1;
-       }
-
-       snprint(buf, sizeof buf, "%s/ipselftab", mntpt);
-       bp = Bopen(buf, OREAD);
-       if (bp != nil) {
-               while ((line = Brdline(bp, '\n')) != nil) {
-                       line[Blinelen(bp) - 1] = '\0';
-                       sp = strchr(line, ' ');
-                       if (sp) {
-                               *sp = '\0';
-                               if (strcmp(addr, line) == 0) {
-                                       dnslog("rejecting my ip %s as local dns server",
-                                               addr);
-                                       return 1;
-                               }
+       Ipifc *ifc;
+       Iplifc *lifc;
+
+       qlock(&ipifclock);
+       for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
+               for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+                       if(ipcmp(ip, lifc->ip) == 0){
+                               qunlock(&ipifclock);
+                               return 1;
                        }
                }
-               Bterm(bp);
        }
+       qunlock(&ipifclock);
+
        return 0;
 }
 
-static char *locdns[20];
-static QLock locdnslck;
-
 static void
-addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
+addlocaldnsserver(DN *dp, int class, char *addr, int i)
 {
-       int n;
-       DN *nsdp;
-       RR *rp;
-       char buf[32];
        uchar ip[IPaddrlen];
+       DN *nsdp, *ipdp;
+       RR *rp, *tp;
+       int type, n;
+       char buf[32];
+
+       if(parseip(ip, addr) == -1 || ipcmp(ip, IPnoaddr) == 0){
+               dnslog("rejecting bad ip %s as local dns server", addr);
+               return;
+       }
 
        /* reject our own ip addresses so we don't query ourselves via udp */
-       if (myaddr(ipaddr))
+       if(myip(ip)){
+               dnslog("rejecting my ip %I as local dns server", ip);
                return;
+       }
 
-       qlock(&locdnslck);
-       for (n = 0; n < i && n < nelem(locdns) && locdns[n]; n++)
-               if (strcmp(locdns[n], ipaddr) == 0) {
-                       dnslog("rejecting duplicate local dns server ip %s",
-                               ipaddr);
-                       qunlock(&locdnslck);
-                       return;
+       /* A or AAAA record */
+       type = isv4(ip) ? Ta : Taaaa;
+       ipdp = ipalookup(ip, class, 1);
+
+       /* check duplicate ip */
+       for(n = 0; n < i; n++){
+               snprint(buf, sizeof buf, "local#dns#server%d", n);
+               nsdp = dnlookup(buf, class, 0);
+               if(nsdp == nil)
+                       continue;
+               rp = rrlookup(nsdp, type, NOneg);
+               for(tp = rp; tp != nil; tp = tp->next){
+                       if(tp->ip == ipdp){
+                               dnslog("rejecting duplicate local dns server ip %I", ip);
+                               rrfreelist(rp);
+                               return;
+                       }
                }
-       if (n < nelem(locdns))
-               if (locdns[n] == nil || ++n < nelem(locdns))
-                       locdns[n] = strdup(ipaddr); /* remember 1st few local ns */
-       qunlock(&locdnslck);
+               rrfreelist(rp);
+       }
+
+       snprint(buf, sizeof buf, "local#dns#server%d", i);
+       nsdp = dnlookup(buf, class, 1);
 
        /* ns record for name server, make up an impossible name */
        rp = rralloc(Tns);
-       snprint(buf, sizeof buf, "%s%d", localserverprefix, i);
-       nsdp = dnlookup(buf, class, 1);
        rp->host = nsdp;
        rp->owner = dp;                 /* e.g., local#dns#servers */
        rp->local = 1;
@@ -902,12 +905,8 @@ addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
        rrattach(rp, Authoritative);    /* will not attach rrs in my area */
        dnagenever(dp);
 
-       /* A or AAAA record */
-       if (parseip(ip, ipaddr) >= 0 && isv4(ip))
-               rp = rralloc(Ta);
-       else
-               rp = rralloc(Taaaa);
-       rp->ip = dnlookup(ipaddr, class, 1);
+       rp = rralloc(type);
+       rp->ip = ipdp;
        rp->owner = nsdp;
        rp->local = 1;
        rp->db = 1;
@@ -915,7 +914,7 @@ addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
        rrattach(rp, Authoritative);    /* will not attach rrs in my area */
        dnagenever(nsdp);
 
-       dnslog("added local dns server %s at %s", buf, ipaddr);
+       dnslog("added local dns server %s at %I", buf, ip);
 }
 
 /*
@@ -927,12 +926,12 @@ dnsservers(int class)
 {
        int i, n;
        char *p;
-       char *args[5];
+       char *args[16];
        Ndbtuple *t, *nt;
        RR *nsrp;
        DN *dp;
 
-       dp = dnlookup(localservers, class, 1);
+       dp = dnlookup("local#dns#servers", class, 1);
        nsrp = rrlookup(dp, Tns, NOneg);
        if(nsrp != nil)
                return nsrp;
@@ -1184,11 +1183,11 @@ insideaddr(char *dom)
        if (dom[0] == '\0' || strcmp(dom, ".") == 0)    /* dns root? */
                return 1;                       /* hack for initialisation */
 
-       lock(&dblock);
+       qlock(&dblock);
        if (indoms == nil)
                loaddomsrvs();
        if (indoms == nil) {
-               unlock(&dblock);
+               qunlock(&dblock);
                return 1;  /* no "inside-dom" sys, try inside nameservers */
        }
 
@@ -1206,7 +1205,7 @@ insideaddr(char *dom)
                        break;
                }
        }
-       unlock(&dblock);
+       qunlock(&dblock);
        return rv;
 }
 
@@ -1218,8 +1217,7 @@ insidens(uchar *ip)
 
        for (t = innmsrvs; t != nil; t = t->entry)
                if (strcmp(t->attr, "ip") == 0) {
-                       parseip(ipa, t->val);
-                       if (memcmp(ipa, ip, sizeof ipa) == 0)
+                       if (parseip(ipa, t->val) != -1 && ipcmp(ipa, ip) == 0)
                                return 1;
                }
        return 0;
@@ -1234,7 +1232,8 @@ outsidensip(int n, uchar *ip)
        i = 0;
        for (t = outnmsrvs; t != nil; t = t->entry)
                if (strcmp(t->attr, "ip") == 0 && i++ == n) {
-                       parseip(ip, t->val);
+                       if (parseip(ip, t->val) == -1)
+                               return -1;
                        return 0;
                }
        return -1;