18 Maxhost= 64, /* maximum host name size */
19 Maxservice= 64, /* maximum service name size */
25 typedef struct Mfile Mfile;
26 typedef struct Mlist Mlist;
27 typedef struct Network Network;
28 typedef struct Flushreq Flushreq;
29 typedef struct Job Job;
31 int vers; /* incremented each clone/attach */
50 * result of the last lookup
83 jmp_buf masterjmp; /* return through here after a slave process has been created */
84 int *isslave; /* *isslave non-zero means this is a slave process */
90 void rattach(Job*, Mfile*);
91 char* rwalk(Job*, Mfile*);
92 void ropen(Job*, Mfile*);
93 void rcreate(Job*, Mfile*);
94 void rread(Job*, Mfile*);
95 void rwrite(Job*, Mfile*);
96 void rclunk(Job*, Mfile*);
97 void rremove(Job*, Mfile*);
98 void rstat(Job*, Mfile*);
99 void rwstat(Job*, Mfile*);
101 void sendmsg(Job*, char*);
103 void mountinit(char*, char*);
108 char *genquery(Mfile*, char*);
109 char* ipinfoquery(Mfile*, char**, int);
110 int needproto(Network*, Ndbtuple*);
112 Ndbtuple* reorder(Ndbtuple*, Ndbtuple*);
114 void readipinterfaces(void);
116 char* estrdup(char*);
119 void setext(char*, int, char*);
120 void cleanmf(Mfile*);
122 extern void paralloc(void);
124 Lock dblock; /* mutex on database operations */
125 Lock netlock; /* mutex for netinit() */
127 char *logfile = "cs";
128 char *paranoiafile = "cs.paranoia";
131 char netndb[Maxpath];
134 * Network specific translators
136 Ndbtuple* iplookup(Network*, char*, char*, int);
137 char* iptrans(Ndbtuple*, Network*, char*, char*, int);
138 Ndbtuple* telcolookup(Network*, char*, char*, int);
139 char* telcotrans(Ndbtuple*, Network*, char*, char*, int);
140 Ndbtuple* dnsiplookup(char*, Ndbs*);
145 Ndbtuple *(*lookup)(Network*, char*, char*, int);
146 char *(*trans)(Ndbtuple*, Network*, char*, char*, int);
147 int considered; /* flag: ignored for "net!"? */
148 int fasttimeouthack; /* flag. was for IL */
158 * net doesn't apply to (r)udp, icmp(v6), or telco (for speed).
160 Network network[] = {
161 [Ntcp] { "tcp", iplookup, iptrans, 0 },
162 { "udp", iplookup, iptrans, 1 },
163 { "icmp", iplookup, iptrans, 1 },
164 { "icmpv6", iplookup, iptrans, 1 },
165 { "rudp", iplookup, iptrans, 1 },
166 { "telco", telcolookup, telcotrans, 1 },
173 char eaddr[16]; /* ascii ethernet address */
174 char ipaddr[64]; /* ascii internet address */
175 uchar ipa[IPaddrlen]; /* binary internet address */
178 Network *netlist; /* networks ordered by preference */
182 nstrcpy(char *to, char *from, int len)
184 strncpy(to, from, len);
191 fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0);
196 * based on libthread's threadsetname, but drags in less library code.
197 * actually just sets the arguments displayed.
200 procsetname(char *fmt, ...)
208 cmdname = vsmprint(fmt, arg);
212 snprint(buf, sizeof buf, "#p/%d/args", getpid());
213 if((fd = open(buf, OWRITE)) >= 0){
214 write(fd, cmdname, strlen(cmdname)+1);
221 main(int argc, char *argv[])
224 char ext[Maxpath], servefile[Maxpath];
227 setnetmtpt(mntpt, sizeof(mntpt), nil);
237 dbfile = EARGF(usage());
243 setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage()));
244 setext(ext, sizeof(ext), mntpt);
250 rfork(RFREND|RFNOTEG);
252 snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
253 snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
254 unmount(servefile, mntpt);
257 fmtinstall('E', eipfmt);
258 fmtinstall('I', eipfmt);
259 fmtinstall('M', eipfmt);
260 fmtinstall('F', fcallfmt);
266 mountinit(servefile, mntpt);
273 * if a mount point is specified, set the cs extention to be the mount point
274 * with '_'s replacing '/'s
277 setext(char *ext, int n, char *p)
282 for(i = 0; i < n; i++){
294 mountinit(char *service, char *mntpt)
301 error("pipe failed");
306 f = create(service, OWRITE|ORCLOSE, 0666);
309 snprint(buf, sizeof(buf), "%d", p[1]);
310 if(write(f, buf, strlen(buf)) != strlen(buf))
311 error("write /srv/cs");
313 switch(rfork(RFFDG|RFPROC|RFNAMEG)){
316 procsetname("%s", mntpt);
319 error("fork failed\n");
322 * put ourselves into the file system
325 if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
326 error("mount failed\n");
329 mfd[0] = mfd[1] = p[0];
335 db = ndbopen(dbfile);
337 error("can't open network database");
339 netdb = ndbopen(netndb);
342 db = ndbcat(netdb, db);
353 for(f = mlist; f; f = f->next)
354 if(f->mf.busy && f->mf.fid == fid)
356 else if(!ff && !f->mf.busy)
359 ff = emalloc(sizeof *f);
364 memset(mf, 0, sizeof *mf);
374 job = mallocz(sizeof(Job), 1);
378 job->request.tag = -1;
389 for(l = &joblist; *l; l = &(*l)->next){
405 for(job = joblist; job; job = job->next){
406 if(job->request.tag == tag && job->request.type != Tflush){
420 uchar mdata[IOHDRSZ + Maxfdata];
424 * if we ask dns to fulfill requests,
425 * a slave process is created to wait for replies. The
426 * master process returns immediately via a longjmp
427 * through 'masterjmp'.
429 * *isslave is a pointer into the call stack to a variable
430 * that tells whether or not the current process is a slave.
432 slaveflag = 0; /* init slave variable */
433 isslave = &slaveflag;
437 n = read9pmsg(mfd[0], mdata, sizeof mdata);
441 if(convM2S(mdata, n, &job->request) != n){
442 syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
443 mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
448 mf = newfid(job->request.fid);
450 syslog(0, logfile, "%F", &job->request);
453 switch(job->request.type){
455 syslog(1, logfile, "unknown request type %d", job->request.type);
502 * slave processes die after replying
506 syslog(0, logfile, "slave death %d", getpid());
515 if(job->request.msize > IOHDRSZ + Maxfdata)
516 job->reply.msize = IOHDRSZ + Maxfdata;
518 job->reply.msize = job->request.msize;
519 if(strncmp(job->request.version, "9P2000", 6) != 0)
520 sendmsg(job, "unknown 9P version");
522 job->reply.version = "9P2000";
530 sendmsg(job, "cs: authentication not required");
534 * don't flush till all the slaves are done
539 flushjob(job->request.oldtag);
544 rattach(Job *job, Mfile *mf)
548 mf->user = estrdup(job->request.uname);
550 mf->qid.vers = vers++;
551 mf->qid.type = QTDIR;
553 job->reply.qid = mf->qid;
559 rwalk(Job *job, Mfile *mf)
570 elems = job->request.wname;
571 nelems = job->request.nwname;
572 job->reply.nwqid = 0;
574 if(job->request.newfid != job->request.fid){
576 nmf = newfid(job->request.newfid);
579 err = "clone to used channel";
583 nmf->user = estrdup(mf->user);
584 nmf->fid = job->request.newfid;
585 nmf->qid.vers = vers++;
588 /* else nmf will be nil */
593 for(i=0; i<nelems && i<MAXWELEM; i++){
594 if((qid.type & QTDIR) == 0){
595 err = "not a directory";
598 if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
602 job->reply.wqid[i] = qid;
606 if(strcmp(elems[i], "cs") == 0){
611 err = "file does not exist";
617 if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
631 ropen(Job *job, Mfile *mf)
637 mode = job->request.mode;
638 if(mf->qid.type & QTDIR){
640 err = "permission denied";
642 job->reply.qid = mf->qid;
643 job->reply.iounit = 0;
648 rcreate(Job *job, Mfile *mf)
651 sendmsg(job, "creation permission denied");
655 rread(Job *job, Mfile *mf)
658 long off, toff, clock;
665 off = job->request.offset;
666 cnt = job->request.count;
667 if(mf->qid.type & QTDIR){
670 memset(&dir, 0, sizeof dir);
672 dir.qid.type = QTFILE;
680 dir.atime = clock; /* wrong */
681 dir.mtime = clock; /* wrong */
682 n = convD2M(&dir, buf, sizeof buf);
684 job->reply.data = (char*)buf;
687 /* look for an answer at the right offset */
689 for(i = 0; mf->reply[i] && i < mf->nreply; i++){
696 break; /* got something to return */
698 /* try looking up more answers */
706 /* give back a single reply (or part of one) */
707 job->reply.data = mf->reply[i] + (off - toff);
708 if(cnt > toff - off + n)
714 job->reply.count = n;
738 for(i = 0; i < mf->nreply; i++){
744 mf->nextnet = netlist;
748 rwrite(Job *job, Mfile *mf)
756 cnt = job->request.count;
757 if(mf->qid.type & QTDIR){
758 err = "can't write directory";
761 if(cnt >= Maxrequest){
762 err = "request too long";
765 job->request.data[cnt] = 0;
770 if(strncmp(job->request.data, "debug", 5)==0){
772 syslog(1, logfile, "debug %d", debug);
777 * toggle ipv6 lookups
779 if(strncmp(job->request.data, "ipv6", 4)==0){
781 syslog(1, logfile, "ipv6lookups %d", ipv6lookups);
788 if(strncmp(job->request.data, "paranoia", 8)==0){
790 syslog(1, logfile, "paranoia %d", paranoia);
795 * add networks to the default list
797 if(strncmp(job->request.data, "add ", 4)==0){
798 if(job->request.data[cnt-1] == '\n')
799 job->request.data[cnt-1] = 0;
800 netadd(job->request.data+4);
808 if(strncmp(job->request.data, "refresh", 7)==0){
813 /* start transaction with a clean slate */
817 * look for a general query
819 if(*job->request.data == '!'){
820 err = genquery(mf, job->request.data+1);
825 syslog(0, logfile, "write %s", job->request.data);
827 syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
832 n = getfields(job->request.data, field, 4, 1, "!");
835 mf->net = strdup("net");
836 mf->host = strdup(field[0]);
839 mf->rem = strdup(field[3]);
842 mf->serv = strdup(field[2]);
845 mf->host = strdup(field[1]);
846 mf->net = strdup(field[0]);
851 * do the first net worth of lookup
854 rerrstr(curerr, sizeof curerr);
858 job->reply.count = cnt;
863 rclunk(Job *job, Mfile *mf)
874 rremove(Job *job, Mfile *mf)
877 sendmsg(job, "remove permission denied");
881 rstat(Job *job, Mfile *mf)
884 uchar buf[IOHDRSZ+Maxfdata];
886 memset(&dir, 0, sizeof dir);
887 if(mf->qid.type & QTDIR){
889 dir.mode = DMDIR|0555;
899 dir.atime = dir.mtime = time(0);
900 job->reply.nstat = convD2M(&dir, buf, sizeof buf);
901 job->reply.stat = buf;
906 rwstat(Job *job, Mfile *mf)
909 sendmsg(job, "wstat permission denied");
913 sendmsg(Job *job, char *err)
916 uchar mdata[IOHDRSZ + Maxfdata];
920 job->reply.type = Rerror;
921 snprint(ename, sizeof(ename), "cs: %s", err);
922 job->reply.ename = ename;
924 job->reply.type = job->request.type+1;
926 job->reply.tag = job->request.tag;
927 n = convS2M(&job->reply, mdata, sizeof mdata);
929 syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
933 if(job->flushed == 0)
934 if(write(mfd[1], mdata, n)!=n)
935 error("mount write");
938 syslog(0, logfile, "%F %d", &job->reply, n);
944 syslog(1, "cs", "%s: %r", s);
951 return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
954 static uchar loopbacknet[IPaddrlen] = {
960 static uchar loopbackmask[IPaddrlen] = {
961 0xff, 0xff, 0xff, 0xff,
962 0xff, 0xff, 0xff, 0xff,
963 0xff, 0xff, 0xff, 0xff,
968 readipinterfaces(void)
970 if(myipaddr(ipa, mntpt) != 0)
971 ipmove(ipa, IPnoaddr);
972 sprint(ipaddr, "%I", ipa);
974 syslog(0, "dns", "ipaddr is %s\n", ipaddr);
978 * get the system name
990 /* use environment, ether addr, or ipaddr to get system name */
993 * environment has priority.
995 * on the sgi power the default system name
996 * is the ip address. ignore that.
999 p = getenv("sysname");
1002 if(strcmp(attr, "ip") != 0)
1003 mysysname = strdup(p);
1007 * the /net/ndb contains what the network
1008 * figured out from DHCP. use that name if
1011 if(mysysname == 0 && netdb != nil){
1013 for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
1014 if(strcmp(t->attr, "sys") == 0){
1015 mysysname = strdup(t->val);
1022 /* next network database, ip address, and ether address to find a name */
1026 free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
1028 for(f = 0; f < 3; f++){
1029 snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
1030 if(myetheraddr(addr, buf) >= 0){
1031 snprint(eaddr, sizeof(eaddr), "%E", addr);
1032 free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
1038 for(tt = t; tt != nil; tt = tt->entry){
1039 if(strcmp(tt->attr, "sys") == 0){
1040 mysysname = strdup(tt->val);
1047 /* nothing else worked, use the ip address */
1048 if(mysysname == 0 && isvalidip(ipa))
1049 mysysname = strdup(ipaddr);
1052 /* set /dev/sysname if we now know it */
1054 f = open("/dev/sysname", OWRITE);
1056 write(f, mysysname, strlen(mysysname));
1064 * Set up a list of default networks by looking for
1068 netinit(int background)
1070 char clone[Maxpath];
1075 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
1084 /* add the mounted networks to the default list */
1085 for(np = network; np->net; np++){
1088 snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
1089 if(access(clone, AEXIST) < 0)
1100 /* find out what our ip address is */
1103 /* set the system name if we need to, these days ip is all we have */
1107 syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
1108 mysysname?mysysname:"???", eaddr, ipaddr, ipa);
1117 * add networks to the standard list
1126 n = getfields(p, field, 12, 1, " ");
1127 for(i = 0; i < n; i++){
1128 for(np = network; np->net; np++){
1129 if(strcmp(field[i], np->net) != 0)
1145 lookforproto(Ndbtuple *t, char *proto)
1147 for(; t != nil; t = t->entry)
1148 if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
1154 * lookup a request. the network "net" means we should pick the
1155 * best network to get there.
1163 char reply[Maxreply];
1167 /* open up the standard db files */
1171 error("can't open mf->network database\n");
1176 return 0; /* must have been a genquery */
1178 if(strcmp(mf->net, "net") == 0){
1180 * go through set of default nets
1182 for(np = mf->nextnet; np; np = np->next){
1183 nt = (*np->lookup)(np, mf->host, mf->serv, 1);
1186 hack = np->fasttimeouthack && !lookforproto(nt, np->net);
1187 for(t = nt; mf->nreply < Nreply && t; t = t->entry){
1188 cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1190 /* avoid duplicates */
1191 for(i = 0; i < mf->nreply; i++)
1192 if(strcmp(mf->reply[i], cp) == 0)
1194 if(i == mf->nreply){
1195 /* save the reply */
1196 mf->replylen[mf->nreply] = strlen(cp);
1197 mf->reply[mf->nreply++] = cp;
1211 * if not /net, we only get one lookup
1216 * look for a specific network
1218 for(np = netlist; np && np->net != nil; np++){
1219 if(np->fasttimeouthack)
1221 if(strcmp(np->net, mf->net) == 0)
1225 if(np && np->net != nil){
1229 nt = (*np->lookup)(np, mf->host, mf->serv, 1);
1230 for(t = nt; mf->nreply < Nreply && t; t = t->entry){
1231 cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
1233 mf->replylen[mf->nreply] = strlen(cp);
1234 mf->reply[mf->nreply++] = cp;
1242 * not a known network, don't translate host or service
1245 snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
1246 mntpt, mf->net, mf->host, mf->serv);
1248 snprint(reply, sizeof(reply), "%s/%s/clone %s",
1249 mntpt, mf->net, mf->host);
1250 mf->reply[0] = strdup(reply);
1251 mf->replylen[0] = strlen(reply);
1258 * translate an ip service name into a port number. If it's a numeric port
1259 * number, look for restricted access.
1261 * the service '*' needs no translation.
1264 ipserv(Network *np, char *name, char *buf, int blen)
1273 /* '*' means any service */
1274 if(strcmp(name, "*")==0){
1279 /* see if it's numeric or symbolic */
1281 for(p = name; *p; p++){
1284 else if(isalpha(*p) || *p == '-' || *p == '$')
1292 p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1296 /* look up only for tcp ports < 1024 to get the restricted
1299 if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
1300 p = ndbgetvalue(db, &s, "port", name, "port", &t);
1306 for(nt = t; nt; nt = nt->entry)
1307 if(strcmp(nt->attr, "restricted") == 0)
1311 snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
1318 * lookup an ip attribute
1321 ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
1328 t = ndbipinfo(db, "ip", ipa, alist, 1);
1331 for(nt = t; nt != nil; nt = nt->entry){
1332 if(strcmp(nt->attr, attr) == 0){
1333 nstrcpy(val, nt->val, vlen);
1339 /* we shouldn't get here */
1345 * lookup (and translate) an ip destination
1348 iplookup(Network *np, char *host, char *serv, int nolookup)
1350 char *attr, *dnsname;
1353 char ts[Maxservice];
1354 char dollar[Maxhost];
1355 uchar ip[IPaddrlen];
1356 uchar net[IPaddrlen];
1357 uchar tnet[IPaddrlen];
1364 * start with the service since it's the most likely to fail
1365 * and costs the least
1367 werrstr("can't translate address");
1368 if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1369 werrstr("can't translate service");
1373 /* for dial strings with no host */
1374 if(strcmp(host, "*") == 0)
1375 return ndbnew("ip", "*");
1378 * hack till we go v6 :: = 0.0.0.0
1380 if(strcmp("::", host) == 0)
1381 return ndbnew("ip", "*");
1384 * '$' means the rest of the name is an attribute that we
1385 * need to search for
1388 if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
1393 * turn '[ip address]' into just 'ip address'
1395 if(*host == '[' && host[strlen(host)-1] == ']'){
1397 host[strlen(host)-1] = 0;
1401 * just accept addresses
1403 attr = ipattr(host);
1404 if(strcmp(attr, "ip") == 0)
1405 return ndbnew("ip", host);
1408 * give the domain name server the first opportunity to
1409 * resolve domain names. if that fails try the database.
1412 werrstr("can't translate address");
1413 if(strcmp(attr, "dom") == 0)
1414 t = dnsiplookup(host, &s);
1416 free(ndbgetvalue(db, &s, attr, host, "ip", &t));
1418 dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
1420 t = dnsiplookup(dnsname, &s);
1425 t = dnsiplookup(host, &s);
1430 * reorder the tuple to have the matched line first and
1431 * save that in the request structure.
1433 t = reorder(t, s.t);
1436 * reorder according to our interfaces
1439 for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
1440 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1441 maskip(lifc->ip, lifc->mask, net);
1442 for(nt = t; nt; nt = nt->entry){
1443 if(strcmp(nt->attr, "ip") != 0)
1445 parseip(ip, nt->val);
1446 maskip(ip, lifc->mask, tnet);
1447 if(memcmp(net, tnet, IPaddrlen) == 0){
1461 * translate an ip address
1464 iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
1466 char ts[Maxservice];
1467 char reply[Maxreply];
1470 if(strcmp(t->attr, "ip") != 0)
1473 if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
1474 werrstr("can't translate service");
1478 snprint(x, sizeof(x), "!%s", rem);
1483 snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
1484 mntpt, np->net, ts, x);
1486 snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
1487 mntpt, np->net, t->val, ts, x, hack? "!fasttimeout": "");
1489 return strdup(reply);
1493 * lookup a telephone number
1496 telcolookup(Network *np, char *host, char *serv, int nolookup)
1501 USED(np, nolookup, serv);
1503 werrstr("can't translate address");
1504 free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
1506 return ndbnew("telco", host);
1508 return reorder(t, s.t);
1512 * translate a telephone address
1515 telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1517 char reply[Maxreply];
1520 if(strcmp(t->attr, "telco") != 0)
1524 snprint(x, sizeof(x), "!%s", rem);
1528 snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
1531 snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
1533 return strdup(reply);
1537 * reorder the tuple to put x's line first in the entry
1540 reorder(Ndbtuple *t, Ndbtuple *x)
1545 /* find start of this entry's line */
1546 for(line = x; line->entry == line->line; line = line->line)
1550 return t; /* already the first line */
1552 /* remove this line and everything after it from the entry */
1553 for(nt = t; nt->entry != line; nt = nt->entry)
1557 /* make that the start of the entry */
1558 for(nt = line; nt->entry; nt = nt->entry)
1565 * create a slave process to handle a request to avoid one request blocking
1566 * another. parent returns to job loop.
1572 return; /* we're already a slave process */
1574 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
1579 syslog(0, logfile, "slave %d", getpid());
1580 procsetname("%s", host);
1584 longjmp(masterjmp, 1);
1590 dnsip6lookup(char *mntpt, char *buf, Ndbtuple *t)
1594 t6 = dnsquery(mntpt, buf, "ipv6"); /* lookup AAAA dns RRs */
1598 /* convert ipv6 attr to ip */
1599 for (tt = t6; tt != nil; tt = tt->entry)
1600 if (strcmp(tt->attr, "ipv6") == 0)
1601 strncpy(tt->attr, "ip", sizeof tt->attr - 1);
1606 /* append t6 list to t list */
1607 for (tt = t; tt->entry != nil; tt = tt->entry)
1614 * call the dns process and have it try to translate a name
1617 dnsiplookup(char *host, Ndbs *s)
1624 /* save the name before starting a slave */
1625 snprint(buf, sizeof(buf), "%s", host);
1629 if(strcmp(ipattr(buf), "ip") == 0)
1630 t = dnsquery(mntpt, buf, "ptr");
1632 t = dnsquery(mntpt, buf, "ip");
1633 /* special case: query ipv6 (AAAA dns RR) too */
1635 t = dnsip6lookup(mntpt, buf, t);
1640 rerrstr(buf, sizeof buf);
1641 if(strstr(buf, "exist"))
1642 werrstr("can't translate address: %s", buf);
1643 else if(strstr(buf, "dns failure"))
1644 werrstr("temporary problem: %s", buf);
1652 qmatch(Ndbtuple *t, char **attr, char **val, int n)
1657 for(i = 1; i < n; i++){
1659 for(nt = t; nt; nt = nt->entry)
1660 if(strcmp(attr[i], nt->attr) == 0)
1661 if(strcmp(val[i], "*") == 0
1662 || strcmp(val[i], nt->val) == 0){
1673 qreply(Mfile *mf, Ndbtuple *t)
1679 for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
1680 s_append(s, nt->attr);
1682 s_append(s, nt->val);
1684 if(nt->line != nt->entry){
1685 mf->replylen[mf->nreply] = s_len(s);
1686 mf->reply[mf->nreply++] = strdup(s_to_c(s));
1700 * generic query lookup. The query is of one of the following
1703 * attr1=val1 attr2=val2 attr3=val3 ...
1705 * returns the matching tuple
1707 * ipinfo attr=val attr1 attr2 attr3 ...
1709 * is like ipinfo and returns the attr{1-n}
1710 * associated with the ip address.
1713 genquery(Mfile *mf, char *query)
1717 char *attr[Maxattr];
1722 n = getfields(query, attr, nelem(attr), 1, " ");
1726 if(strcmp(attr[0], "ipinfo") == 0)
1727 return ipinfoquery(mf, attr, n);
1730 for(i = 0; i < n; i++){
1731 p = strchr(attr[i], '=');
1738 /* give dns a chance */
1739 if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
1740 t = dnsiplookup(val[0], &s);
1742 if(qmatch(t, attr, val, n)){
1751 /* first pair is always the key. It can't be a '*' */
1752 t = ndbsearch(db, &s, attr[0], val[0]);
1754 /* search is the and of all the pairs */
1756 if(qmatch(t, attr, val, n)){
1763 t = ndbsnext(&s, attr[0], val[0]);
1770 * resolve an ip address
1773 ipresolve(char *attr, char *host)
1775 Ndbtuple *t, *nt, **l;
1777 t = iplookup(&network[Ntcp], host, "*", 0);
1778 for(l = &t; *l != nil; ){
1780 if(strcmp(nt->attr, "ip") != 0){
1786 strcpy(nt->attr, attr);
1793 ipinfoquery(Mfile *mf, char **list, int n)
1796 int resolve[Maxattr];
1797 Ndbtuple *t, *nt, **l;
1806 /* get search attribute=value, or assume ip=myipaddr */
1808 if((val = strchr(attr, '=')) != nil){
1821 * don't let ndbipinfo resolve the addresses, we're
1825 for(i = 0; i < n; i++)
1826 if(*list[i] == '@'){ /* @attr=val ? */
1828 resolve[i] = 1; /* we'll resolve it */
1833 t = ndbipinfo(db, attr, val, list, n);
1838 for(l = &t; *l != nil;){
1841 /* already an address? */
1842 if(strcmp(ipattr(nt->val), "ip") == 0){
1847 /* user wants it resolved? */
1848 for(i = 0; i < n; i++)
1849 if(strcmp(list[i], nt->attr) == 0)
1851 if(i >= n || resolve[i] == 0){
1856 /* resolve address and replace entry */
1857 *l = ipresolve(nt->attr, nt->val);
1867 /* make it all one line */
1868 for(nt = t; nt != nil; nt = nt->entry){
1869 if(nt->entry == nil)
1872 nt->line = nt->entry;
1902 memmove(p, s, size);