13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3219b2ee8SDavid du Colombier #include <auth.h> 43e12c5d1SDavid du Colombier #include <fcall.h> 53e12c5d1SDavid du Colombier #include <bio.h> 63e12c5d1SDavid du Colombier #include <ctype.h> 77dd7cddfSDavid du Colombier #include <ip.h> 89a747e4fSDavid du Colombier #include <pool.h> 93e12c5d1SDavid du Colombier #include "dns.h" 103e12c5d1SDavid du Colombier 113e12c5d1SDavid du Colombier enum 123e12c5d1SDavid du Colombier { 139a747e4fSDavid du Colombier Maxrequest= 1024, 1476783259SDavid du Colombier Maxreply= 8192, /* was 512 */ 1576783259SDavid du Colombier Maxrrr= 32, /* was 16 */ 169a747e4fSDavid du Colombier Maxfdata= 8192, 173e12c5d1SDavid du Colombier 18f46c709fSDavid du Colombier Defmaxage= 60*60, /* default domain name max. age */ 194f8f669cSDavid du Colombier 209a747e4fSDavid du Colombier Qdir= 0, 213e12c5d1SDavid du Colombier Qdns= 1, 223e12c5d1SDavid du Colombier }; 233e12c5d1SDavid du Colombier 243e12c5d1SDavid du Colombier typedef struct Mfile Mfile; 257dd7cddfSDavid du Colombier typedef struct Job Job; 263e12c5d1SDavid du Colombier typedef struct Network Network; 273e12c5d1SDavid du Colombier 283e12c5d1SDavid du Colombier int vers; /* incremented each clone/attach */ 29adb31a62SDavid du Colombier 30adb31a62SDavid du Colombier static volatile int stop; 313e12c5d1SDavid du Colombier 32410ea80bSDavid du Colombier /* holds data to be returned via read of /net/dns, perhaps multiple reads */ 333e12c5d1SDavid du Colombier struct Mfile 343e12c5d1SDavid du Colombier { 357dd7cddfSDavid du Colombier Mfile *next; /* next free mfile */ 369a747e4fSDavid du Colombier int ref; 377dd7cddfSDavid du Colombier 389a747e4fSDavid du Colombier char *user; 393e12c5d1SDavid du Colombier Qid qid; 403e12c5d1SDavid du Colombier int fid; 413e12c5d1SDavid du Colombier 423e12c5d1SDavid du Colombier int type; /* reply type */ 437dd7cddfSDavid du Colombier char reply[Maxreply]; 447dd7cddfSDavid du Colombier ushort rr[Maxrrr]; /* offset of rr's */ 457dd7cddfSDavid du Colombier ushort nrr; /* number of rr's */ 463e12c5d1SDavid du Colombier }; 473e12c5d1SDavid du Colombier 484f8f669cSDavid du Colombier /* 494f8f669cSDavid du Colombier * active local requests 504f8f669cSDavid du Colombier */ 517dd7cddfSDavid du Colombier struct Job 527dd7cddfSDavid du Colombier { 537dd7cddfSDavid du Colombier Job *next; 547dd7cddfSDavid du Colombier int flushed; 557dd7cddfSDavid du Colombier Fcall request; 567dd7cddfSDavid du Colombier Fcall reply; 577dd7cddfSDavid du Colombier }; 587dd7cddfSDavid du Colombier Lock joblock; 597dd7cddfSDavid du Colombier Job *joblist; 607dd7cddfSDavid du Colombier 617dd7cddfSDavid du Colombier struct { 627dd7cddfSDavid du Colombier Lock; 637dd7cddfSDavid du Colombier Mfile *inuse; /* active mfile's */ 647dd7cddfSDavid du Colombier } mfalloc; 657dd7cddfSDavid du Colombier 664f8f669cSDavid du Colombier Cfg cfg; 676b0d5c8bSDavid du Colombier int debug; 684f8f669cSDavid du Colombier uchar ipaddr[IPaddrlen]; /* my ip address */ 694f8f669cSDavid du Colombier int maxage = Defmaxage; 704f8f669cSDavid du Colombier int mfd[2]; 714f8f669cSDavid du Colombier int needrefresh; 727dd7cddfSDavid du Colombier ulong now; 73a41547ffSDavid du Colombier vlong nowns; 744f8f669cSDavid du Colombier int sendnotifies; 757dd7cddfSDavid du Colombier int testing; 767dd7cddfSDavid du Colombier char *trace; 774f8f669cSDavid du Colombier int traceactivity; 78dc5a79c1SDavid du Colombier char *zonerefreshprogram; 793e12c5d1SDavid du Colombier 804f8f669cSDavid du Colombier char *logfile = "dns"; /* or "dns.test" */ 816b0d5c8bSDavid du Colombier char *dbfile; 826b0d5c8bSDavid du Colombier char mntpt[Maxpath]; 834f8f669cSDavid du Colombier 844f8f669cSDavid du Colombier int fillreply(Mfile*, int); 854f8f669cSDavid du Colombier void freejob(Job*); 864f8f669cSDavid du Colombier void io(void); 874f8f669cSDavid du Colombier void mountinit(char*, char*); 884f8f669cSDavid du Colombier Job* newjob(void); 894f8f669cSDavid du Colombier void rattach(Job*, Mfile*); 904f8f669cSDavid du Colombier void rauth(Job*); 914f8f669cSDavid du Colombier void rclunk(Job*, Mfile*); 924f8f669cSDavid du Colombier void rcreate(Job*, Mfile*); 934f8f669cSDavid du Colombier void rflush(Job*); 944f8f669cSDavid du Colombier void ropen(Job*, Mfile*); 954f8f669cSDavid du Colombier void rread(Job*, Mfile*); 964f8f669cSDavid du Colombier void rremove(Job*, Mfile*); 974f8f669cSDavid du Colombier void rstat(Job*, Mfile*); 984f8f669cSDavid du Colombier void rversion(Job*); 994f8f669cSDavid du Colombier char* rwalk(Job*, Mfile*); 1004f8f669cSDavid du Colombier void rwrite(Job*, Mfile*, Request*); 1014f8f669cSDavid du Colombier void rwstat(Job*, Mfile*); 1024f8f669cSDavid du Colombier void sendmsg(Job*, char*); 1034f8f669cSDavid du Colombier void setext(char*, int, char*); 1046b0d5c8bSDavid du Colombier 1057dd7cddfSDavid du Colombier void 1067dd7cddfSDavid du Colombier usage(void) 1077dd7cddfSDavid du Colombier { 108a41547ffSDavid du Colombier fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] " 109410ea80bSDavid du Colombier "[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0); 1107dd7cddfSDavid du Colombier exits("usage"); 1117dd7cddfSDavid du Colombier } 112219b2ee8SDavid du Colombier 113410ea80bSDavid du Colombier int addforwtarg(char *); 114410ea80bSDavid du Colombier 1153e12c5d1SDavid du Colombier void 1163e12c5d1SDavid du Colombier main(int argc, char *argv[]) 1173e12c5d1SDavid du Colombier { 118c73252aeSDavid du Colombier int kid, pid; 1194f8f669cSDavid du Colombier char servefile[Maxpath], ext[Maxpath]; 12014cc0f53SDavid du Colombier Dir *dir; 121219b2ee8SDavid du Colombier 1224f8f669cSDavid du Colombier setnetmtpt(mntpt, sizeof mntpt, nil); 1237dd7cddfSDavid du Colombier ext[0] = 0; 1243e12c5d1SDavid du Colombier ARGBEGIN{ 1254f8f669cSDavid du Colombier case 'a': 1264f8f669cSDavid du Colombier maxage = atol(EARGF(usage())); 1274f8f669cSDavid du Colombier if (maxage <= 0) 1284f8f669cSDavid du Colombier maxage = Defmaxage; 1294f8f669cSDavid du Colombier break; 1303e12c5d1SDavid du Colombier case 'd': 1313e12c5d1SDavid du Colombier debug = 1; 13239734e7eSDavid du Colombier traceactivity = 1; 1333e12c5d1SDavid du Colombier break; 134219b2ee8SDavid du Colombier case 'f': 1354f8f669cSDavid du Colombier dbfile = EARGF(usage()); 1367dd7cddfSDavid du Colombier break; 137a41547ffSDavid du Colombier case 'F': 138a41547ffSDavid du Colombier cfg.justforw = cfg.resolver = 1; 139a41547ffSDavid du Colombier break; 1404f8f669cSDavid du Colombier case 'n': 1414f8f669cSDavid du Colombier sendnotifies = 1; 1424f8f669cSDavid du Colombier break; 1434f8f669cSDavid du Colombier case 'N': 1444f8f669cSDavid du Colombier target = atol(EARGF(usage())); 145a41547ffSDavid du Colombier if (target < 1000) 146a41547ffSDavid du Colombier target = 1000; 1474f8f669cSDavid du Colombier break; 1484f8f669cSDavid du Colombier case 'o': 1494f8f669cSDavid du Colombier cfg.straddle = 1; /* straddle inside & outside networks */ 1504fafed5dSDavid du Colombier break; 1517dd7cddfSDavid du Colombier case 'r': 1524f8f669cSDavid du Colombier cfg.resolver = 1; 153219b2ee8SDavid du Colombier break; 154b85a8364SDavid du Colombier case 'R': 155b85a8364SDavid du Colombier norecursion = 1; 156b85a8364SDavid du Colombier break; 1573e12c5d1SDavid du Colombier case 's': 1584f8f669cSDavid du Colombier cfg.serve = 1; /* serve network */ 1594f8f669cSDavid du Colombier cfg.cachedb = 1; 1606b0d5c8bSDavid du Colombier break; 1617dd7cddfSDavid du Colombier case 't': 1627dd7cddfSDavid du Colombier testing = 1; 1633e12c5d1SDavid du Colombier break; 164410ea80bSDavid du Colombier case 'T': 165410ea80bSDavid du Colombier addforwtarg(EARGF(usage())); 166410ea80bSDavid du Colombier break; 1674f8f669cSDavid du Colombier case 'x': 1684f8f669cSDavid du Colombier setnetmtpt(mntpt, sizeof mntpt, EARGF(usage())); 1694f8f669cSDavid du Colombier setext(ext, sizeof ext, mntpt); 1706b0d5c8bSDavid du Colombier break; 1714f8f669cSDavid du Colombier case 'z': 1724f8f669cSDavid du Colombier zonerefreshprogram = EARGF(usage()); 173dc5a79c1SDavid du Colombier break; 1743e12c5d1SDavid du Colombier }ARGEND 1753e12c5d1SDavid du Colombier USED(argc); 1763e12c5d1SDavid du Colombier USED(argv); 1773e12c5d1SDavid du Colombier 1784f8f669cSDavid du Colombier if(testing) 1794f8f669cSDavid du Colombier mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM; 1806aaebd7dSDavid du Colombier mainmem->flags |= POOL_ANTAGONISM; 1817dd7cddfSDavid du Colombier rfork(RFREND|RFNOTEG); 1823e12c5d1SDavid du Colombier 1834f8f669cSDavid du Colombier cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0); 1844f8f669cSDavid du Colombier 1857dd7cddfSDavid du Colombier /* start syslog before we fork */ 1869a747e4fSDavid du Colombier fmtinstall('F', fcallfmt); 187219b2ee8SDavid du Colombier dninit(); 18876783259SDavid du Colombier /* this really shouldn't be fatal */ 1899a747e4fSDavid du Colombier if(myipaddr(ipaddr, mntpt) < 0) 1907dd7cddfSDavid du Colombier sysfatal("can't read my ip address"); 191a41547ffSDavid du Colombier dnslog("starting %s%sdns %s%s%son %I's %s", 1924f8f669cSDavid du Colombier (cfg.straddle? "straddling ": ""), 1934f8f669cSDavid du Colombier (cfg.cachedb? "caching ": ""), 1944f8f669cSDavid du Colombier (cfg.serve? "udp server ": ""), 195a41547ffSDavid du Colombier (cfg.justforw? "forwarding-only ": ""), 1964f8f669cSDavid du Colombier (cfg.resolver? "resolver ": ""), ipaddr, mntpt); 1977dd7cddfSDavid du Colombier 1987dd7cddfSDavid du Colombier opendatabase(); 199a41547ffSDavid du Colombier now = time(nil); /* open time files before we fork */ 200a41547ffSDavid du Colombier nowns = nsec(); 2017dd7cddfSDavid du Colombier 2024f8f669cSDavid du Colombier snprint(servefile, sizeof servefile, "#s/dns%s", ext); 20314cc0f53SDavid du Colombier dir = dirstat(servefile); 20414cc0f53SDavid du Colombier if (dir) 20514cc0f53SDavid du Colombier sysfatal("%s exists; another dns instance is running", 20614cc0f53SDavid du Colombier servefile); 20714cc0f53SDavid du Colombier free(dir); 20814cc0f53SDavid du Colombier // unmount(servefile, mntpt); 20914cc0f53SDavid du Colombier // remove(servefile); 21014cc0f53SDavid du Colombier 211c73252aeSDavid du Colombier mountinit(servefile, mntpt); /* forks, parent exits */ 2127dd7cddfSDavid du Colombier 2137dd7cddfSDavid du Colombier srand(now*getpid()); 2147dd7cddfSDavid du Colombier db2cache(1); 215410ea80bSDavid du Colombier // dnageallnever(); 2167dd7cddfSDavid du Colombier 2174f8f669cSDavid du Colombier if (cfg.straddle && !seerootns()) 2184f8f669cSDavid du Colombier dnslog("straddle server misconfigured; can't see root name servers"); 219c73252aeSDavid du Colombier /* 220c73252aeSDavid du Colombier * fork without sharing heap. 221c73252aeSDavid du Colombier * parent waits around for child to die, then forks & restarts. 222c73252aeSDavid du Colombier * child may spawn udp server, notify procs, etc.; when it gets too 223c73252aeSDavid du Colombier * big, it kills itself and any children. 224c73252aeSDavid du Colombier * /srv/dns and /net/dns remain open and valid. 225c73252aeSDavid du Colombier */ 226c73252aeSDavid du Colombier for (;;) { 227c73252aeSDavid du Colombier kid = rfork(RFPROC|RFFDG|RFNOTEG); 228c73252aeSDavid du Colombier switch (kid) { 229c73252aeSDavid du Colombier case -1: 230c73252aeSDavid du Colombier sysfatal("fork failed: %r"); 231c73252aeSDavid du Colombier case 0: 2324f8f669cSDavid du Colombier if(cfg.serve) 2337dd7cddfSDavid du Colombier dnudpserver(mntpt); 234dc5a79c1SDavid du Colombier if(sendnotifies) 235dc5a79c1SDavid du Colombier notifyproc(); 2363e12c5d1SDavid du Colombier io(); 237c73252aeSDavid du Colombier _exits("restart"); 238c73252aeSDavid du Colombier default: 239c73252aeSDavid du Colombier while ((pid = waitpid()) != kid && pid != -1) 240c73252aeSDavid du Colombier continue; 241c73252aeSDavid du Colombier break; 242c73252aeSDavid du Colombier } 243c73252aeSDavid du Colombier dnslog("dns restarting"); 244c73252aeSDavid du Colombier } 2453e12c5d1SDavid du Colombier } 2463e12c5d1SDavid du Colombier 2477dd7cddfSDavid du Colombier /* 2484f8f669cSDavid du Colombier * if a mount point is specified, set the cs extension to be the mount point 2497dd7cddfSDavid du Colombier * with '_'s replacing '/'s 2507dd7cddfSDavid du Colombier */ 2513e12c5d1SDavid du Colombier void 2527dd7cddfSDavid du Colombier setext(char *ext, int n, char *p) 2537dd7cddfSDavid du Colombier { 2547dd7cddfSDavid du Colombier int i, c; 2557dd7cddfSDavid du Colombier 2567dd7cddfSDavid du Colombier n--; 2577dd7cddfSDavid du Colombier for(i = 0; i < n; i++){ 2587dd7cddfSDavid du Colombier c = p[i]; 2597dd7cddfSDavid du Colombier if(c == 0) 2607dd7cddfSDavid du Colombier break; 2617dd7cddfSDavid du Colombier if(c == '/') 2627dd7cddfSDavid du Colombier c = '_'; 2637dd7cddfSDavid du Colombier ext[i] = c; 2647dd7cddfSDavid du Colombier } 2657dd7cddfSDavid du Colombier ext[i] = 0; 2667dd7cddfSDavid du Colombier } 2677dd7cddfSDavid du Colombier 2687dd7cddfSDavid du Colombier void 2697dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt) 2703e12c5d1SDavid du Colombier { 2713e12c5d1SDavid du Colombier int f; 2723e12c5d1SDavid du Colombier int p[2]; 2733e12c5d1SDavid du Colombier char buf[32]; 2743e12c5d1SDavid du Colombier 2753e12c5d1SDavid du Colombier if(pipe(p) < 0) 2767dd7cddfSDavid du Colombier abort(); /* "pipe failed" */; 277c73252aeSDavid du Colombier /* copy namespace to avoid a deadlock */ 278219b2ee8SDavid du Colombier switch(rfork(RFFDG|RFPROC|RFNAMEG)){ 279c73252aeSDavid du Colombier case 0: /* child: hang around and (re)start main proc */ 280219b2ee8SDavid du Colombier close(p[1]); 2816aaebd7dSDavid du Colombier procsetname("%s restarter", mntpt); 2823e12c5d1SDavid du Colombier break; 2833e12c5d1SDavid du Colombier case -1: 2847dd7cddfSDavid du Colombier abort(); /* "fork failed\n" */; 285c73252aeSDavid du Colombier default: /* parent: make /srv/dns, mount it, exit */ 286219b2ee8SDavid du Colombier close(p[0]); 287219b2ee8SDavid du Colombier 2883e12c5d1SDavid du Colombier /* 2893e12c5d1SDavid du Colombier * make a /srv/dns 2903e12c5d1SDavid du Colombier */ 2913e12c5d1SDavid du Colombier f = create(service, 1, 0666); 2923e12c5d1SDavid du Colombier if(f < 0) 2937dd7cddfSDavid du Colombier abort(); /* service */; 2944f8f669cSDavid du Colombier snprint(buf, sizeof buf, "%d", p[1]); 2953e12c5d1SDavid du Colombier if(write(f, buf, strlen(buf)) != strlen(buf)) 2967dd7cddfSDavid du Colombier abort(); /* "write %s", service */; 2973e12c5d1SDavid du Colombier close(f); 2983e12c5d1SDavid du Colombier 2993e12c5d1SDavid du Colombier /* 3003e12c5d1SDavid du Colombier * put ourselves into the file system 3013e12c5d1SDavid du Colombier */ 3029a747e4fSDavid du Colombier if(mount(p[1], -1, mntpt, MAFTER, "") < 0) 3039a747e4fSDavid du Colombier fprint(2, "dns mount failed: %r\n"); 304219b2ee8SDavid du Colombier _exits(0); 3053e12c5d1SDavid du Colombier } 3063e12c5d1SDavid du Colombier mfd[0] = mfd[1] = p[0]; 3073e12c5d1SDavid du Colombier } 3083e12c5d1SDavid du Colombier 3093e12c5d1SDavid du Colombier Mfile* 3107dd7cddfSDavid du Colombier newfid(int fid, int needunused) 3113e12c5d1SDavid du Colombier { 3123e12c5d1SDavid du Colombier Mfile *mf; 3133e12c5d1SDavid du Colombier 3147dd7cddfSDavid du Colombier lock(&mfalloc); 3154f8f669cSDavid du Colombier for(mf = mfalloc.inuse; mf != nil; mf = mf->next) 3167dd7cddfSDavid du Colombier if(mf->fid == fid){ 3177dd7cddfSDavid du Colombier unlock(&mfalloc); 3187dd7cddfSDavid du Colombier if(needunused) 3197dd7cddfSDavid du Colombier return nil; 3203e12c5d1SDavid du Colombier return mf; 3213e12c5d1SDavid du Colombier } 3229a747e4fSDavid du Colombier mf = emalloc(sizeof(*mf)); 3233e12c5d1SDavid du Colombier mf->fid = fid; 324c73252aeSDavid du Colombier mf->user = estrdup("dummy"); 325*530fef66SDavid du Colombier mf->next = mfalloc.inuse; 3267dd7cddfSDavid du Colombier mfalloc.inuse = mf; 3277dd7cddfSDavid du Colombier unlock(&mfalloc); 3283e12c5d1SDavid du Colombier return mf; 3293e12c5d1SDavid du Colombier } 3303e12c5d1SDavid du Colombier 3313e12c5d1SDavid du Colombier void 3327dd7cddfSDavid du Colombier freefid(Mfile *mf) 3337dd7cddfSDavid du Colombier { 3347dd7cddfSDavid du Colombier Mfile **l; 3357dd7cddfSDavid du Colombier 3367dd7cddfSDavid du Colombier lock(&mfalloc); 3374f8f669cSDavid du Colombier for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next) 3387dd7cddfSDavid du Colombier if(*l == mf){ 3397dd7cddfSDavid du Colombier *l = mf->next; 3406b0d5c8bSDavid du Colombier if(mf->user) 3419a747e4fSDavid du Colombier free(mf->user); 3424f8f669cSDavid du Colombier memset(mf, 0, sizeof *mf); /* cause trouble */ 3437dd7cddfSDavid du Colombier free(mf); 3447dd7cddfSDavid du Colombier unlock(&mfalloc); 3457dd7cddfSDavid du Colombier return; 3467dd7cddfSDavid du Colombier } 347*530fef66SDavid du Colombier unlock(&mfalloc); 3487dd7cddfSDavid du Colombier sysfatal("freeing unused fid"); 3497dd7cddfSDavid du Colombier } 3507dd7cddfSDavid du Colombier 3517dd7cddfSDavid du Colombier Mfile* 3527dd7cddfSDavid du Colombier copyfid(Mfile *mf, int fid) 3537dd7cddfSDavid du Colombier { 3547dd7cddfSDavid du Colombier Mfile *nmf; 3557dd7cddfSDavid du Colombier 3567dd7cddfSDavid du Colombier nmf = newfid(fid, 1); 3577dd7cddfSDavid du Colombier if(nmf == nil) 3587dd7cddfSDavid du Colombier return nil; 3597dd7cddfSDavid du Colombier nmf->fid = fid; 360*530fef66SDavid du Colombier free(nmf->user); /* estrdup("dummy") */ 3619a747e4fSDavid du Colombier nmf->user = estrdup(mf->user); 3629a747e4fSDavid du Colombier nmf->qid.type = mf->qid.type; 3637dd7cddfSDavid du Colombier nmf->qid.path = mf->qid.path; 3647dd7cddfSDavid du Colombier nmf->qid.vers = vers++; 3657dd7cddfSDavid du Colombier return nmf; 3667dd7cddfSDavid du Colombier } 3677dd7cddfSDavid du Colombier 3687dd7cddfSDavid du Colombier Job* 3697dd7cddfSDavid du Colombier newjob(void) 3707dd7cddfSDavid du Colombier { 3717dd7cddfSDavid du Colombier Job *job; 3727dd7cddfSDavid du Colombier 3734f8f669cSDavid du Colombier job = emalloc(sizeof *job); 3747dd7cddfSDavid du Colombier lock(&joblock); 3757dd7cddfSDavid du Colombier job->next = joblist; 3767dd7cddfSDavid du Colombier joblist = job; 3777dd7cddfSDavid du Colombier job->request.tag = -1; 3787dd7cddfSDavid du Colombier unlock(&joblock); 3797dd7cddfSDavid du Colombier return job; 3807dd7cddfSDavid du Colombier } 3817dd7cddfSDavid du Colombier 3827dd7cddfSDavid du Colombier void 3837dd7cddfSDavid du Colombier freejob(Job *job) 3847dd7cddfSDavid du Colombier { 3857dd7cddfSDavid du Colombier Job **l; 3867dd7cddfSDavid du Colombier 3877dd7cddfSDavid du Colombier lock(&joblock); 3884f8f669cSDavid du Colombier for(l = &joblist; *l; l = &(*l)->next) 3894f8f669cSDavid du Colombier if(*l == job){ 3907dd7cddfSDavid du Colombier *l = job->next; 3914f8f669cSDavid du Colombier memset(job, 0, sizeof *job); /* cause trouble */ 3927dd7cddfSDavid du Colombier free(job); 3937dd7cddfSDavid du Colombier break; 3947dd7cddfSDavid du Colombier } 3957dd7cddfSDavid du Colombier unlock(&joblock); 3967dd7cddfSDavid du Colombier } 3977dd7cddfSDavid du Colombier 3987dd7cddfSDavid du Colombier void 3997dd7cddfSDavid du Colombier flushjob(int tag) 4007dd7cddfSDavid du Colombier { 4017dd7cddfSDavid du Colombier Job *job; 4027dd7cddfSDavid du Colombier 4037dd7cddfSDavid du Colombier lock(&joblock); 4044f8f669cSDavid du Colombier for(job = joblist; job; job = job->next) 4057dd7cddfSDavid du Colombier if(job->request.tag == tag && job->request.type != Tflush){ 4067dd7cddfSDavid du Colombier job->flushed = 1; 4077dd7cddfSDavid du Colombier break; 4087dd7cddfSDavid du Colombier } 4097dd7cddfSDavid du Colombier unlock(&joblock); 4107dd7cddfSDavid du Colombier } 4117dd7cddfSDavid du Colombier 4127dd7cddfSDavid du Colombier void 4133e12c5d1SDavid du Colombier io(void) 4143e12c5d1SDavid du Colombier { 415225077b0SDavid du Colombier volatile long n; 416225077b0SDavid du Colombier volatile uchar mdata[IOHDRSZ + Maxfdata]; 417225077b0SDavid du Colombier Job *volatile job; 418225077b0SDavid du Colombier Mfile *volatile mf; 419225077b0SDavid du Colombier volatile Request req; 4203e12c5d1SDavid du Colombier 4214f8f669cSDavid du Colombier memset(&req, 0, sizeof req); 4223e12c5d1SDavid du Colombier /* 4233e12c5d1SDavid du Colombier * a slave process is sometimes forked to wait for replies from other 4243e12c5d1SDavid du Colombier * servers. The master process returns immediately via a longjmp 425219b2ee8SDavid du Colombier * through 'mret'. 4263e12c5d1SDavid du Colombier */ 4277dd7cddfSDavid du Colombier if(setjmp(req.mret)) 428b4b9fc2fSDavid du Colombier putactivity(0); 4293e12c5d1SDavid du Colombier req.isslave = 0; 430c73252aeSDavid du Colombier stop = 0; 431c73252aeSDavid du Colombier while(!stop){ 432f2714ceaSDavid du Colombier procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms", 433f2714ceaSDavid du Colombier stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms); 4349a747e4fSDavid du Colombier n = read9pmsg(mfd[0], mdata, sizeof mdata); 4357dd7cddfSDavid du Colombier if(n<=0){ 436adb31a62SDavid du Colombier dnslog("error reading 9P from %s: %r", mntpt); 437adb31a62SDavid du Colombier sleep(2000); /* don't thrash */ 4386aaebd7dSDavid du Colombier return; 4397dd7cddfSDavid du Colombier } 4404f8f669cSDavid du Colombier 4416aaebd7dSDavid du Colombier stats.qrecvd9prpc++; 4427dd7cddfSDavid du Colombier job = newjob(); 4439a747e4fSDavid du Colombier if(convM2S(mdata, n, &job->request) != n){ 4447dd7cddfSDavid du Colombier freejob(job); 4457dd7cddfSDavid du Colombier continue; 4467dd7cddfSDavid du Colombier } 4477dd7cddfSDavid du Colombier mf = newfid(job->request.fid, 0); 448219b2ee8SDavid du Colombier if(debug) 4494f8f669cSDavid du Colombier dnslog("%F", &job->request); 4507dd7cddfSDavid du Colombier 451b4b9fc2fSDavid du Colombier getactivity(&req, 0); 452254fe3d3SDavid du Colombier req.aborttime = time(nil) + Maxreqtm; 453f46c709fSDavid du Colombier req.from = "9p"; 4547dd7cddfSDavid du Colombier 4557dd7cddfSDavid du Colombier switch(job->request.type){ 4563e12c5d1SDavid du Colombier default: 4574f8f669cSDavid du Colombier warning("unknown request type %d", job->request.type); 4583e12c5d1SDavid du Colombier break; 4599a747e4fSDavid du Colombier case Tversion: 4609a747e4fSDavid du Colombier rversion(job); 4613e12c5d1SDavid du Colombier break; 4629a747e4fSDavid du Colombier case Tauth: 4639a747e4fSDavid du Colombier rauth(job); 4643e12c5d1SDavid du Colombier break; 4653e12c5d1SDavid du Colombier case Tflush: 4667dd7cddfSDavid du Colombier rflush(job); 4673e12c5d1SDavid du Colombier break; 4683e12c5d1SDavid du Colombier case Tattach: 4697dd7cddfSDavid du Colombier rattach(job, mf); 4703e12c5d1SDavid du Colombier break; 4713e12c5d1SDavid du Colombier case Twalk: 4727dd7cddfSDavid du Colombier rwalk(job, mf); 4733e12c5d1SDavid du Colombier break; 4743e12c5d1SDavid du Colombier case Topen: 4757dd7cddfSDavid du Colombier ropen(job, mf); 4763e12c5d1SDavid du Colombier break; 4773e12c5d1SDavid du Colombier case Tcreate: 4787dd7cddfSDavid du Colombier rcreate(job, mf); 4793e12c5d1SDavid du Colombier break; 4803e12c5d1SDavid du Colombier case Tread: 4817dd7cddfSDavid du Colombier rread(job, mf); 4823e12c5d1SDavid du Colombier break; 4833e12c5d1SDavid du Colombier case Twrite: 484adb31a62SDavid du Colombier /* &req is handed to dnresolve() */ 4857dd7cddfSDavid du Colombier rwrite(job, mf, &req); 4863e12c5d1SDavid du Colombier break; 4873e12c5d1SDavid du Colombier case Tclunk: 4887dd7cddfSDavid du Colombier rclunk(job, mf); 4893e12c5d1SDavid du Colombier break; 4903e12c5d1SDavid du Colombier case Tremove: 4917dd7cddfSDavid du Colombier rremove(job, mf); 4923e12c5d1SDavid du Colombier break; 4933e12c5d1SDavid du Colombier case Tstat: 4947dd7cddfSDavid du Colombier rstat(job, mf); 4953e12c5d1SDavid du Colombier break; 4963e12c5d1SDavid du Colombier case Twstat: 4977dd7cddfSDavid du Colombier rwstat(job, mf); 4983e12c5d1SDavid du Colombier break; 4993e12c5d1SDavid du Colombier } 5007dd7cddfSDavid du Colombier 5017dd7cddfSDavid du Colombier freejob(job); 5027dd7cddfSDavid du Colombier 5033e12c5d1SDavid du Colombier /* 5043e12c5d1SDavid du Colombier * slave processes die after replying 5053e12c5d1SDavid du Colombier */ 5067dd7cddfSDavid du Colombier if(req.isslave){ 507b4b9fc2fSDavid du Colombier putactivity(0); 5083e12c5d1SDavid du Colombier _exits(0); 5097dd7cddfSDavid du Colombier } 5107dd7cddfSDavid du Colombier 511b4b9fc2fSDavid du Colombier putactivity(0); 5127dd7cddfSDavid du Colombier } 513c73252aeSDavid du Colombier /* kill any udp server, notifier, etc. processes */ 514c73252aeSDavid du Colombier postnote(PNGROUP, getpid(), "die"); 515c73252aeSDavid du Colombier sleep(1000); 5163e12c5d1SDavid du Colombier } 5173e12c5d1SDavid du Colombier 5183e12c5d1SDavid du Colombier void 5199a747e4fSDavid du Colombier rversion(Job *job) 520219b2ee8SDavid du Colombier { 5219a747e4fSDavid du Colombier if(job->request.msize > IOHDRSZ + Maxfdata) 5229a747e4fSDavid du Colombier job->reply.msize = IOHDRSZ + Maxfdata; 5239a747e4fSDavid du Colombier else 5249a747e4fSDavid du Colombier job->reply.msize = job->request.msize; 5259a747e4fSDavid du Colombier if(strncmp(job->request.version, "9P2000", 6) != 0) 5269a747e4fSDavid du Colombier sendmsg(job, "unknown 9P version"); 5279a747e4fSDavid du Colombier else{ 5289a747e4fSDavid du Colombier job->reply.version = "9P2000"; 5297dd7cddfSDavid du Colombier sendmsg(job, 0); 530219b2ee8SDavid du Colombier } 5319a747e4fSDavid du Colombier } 532219b2ee8SDavid du Colombier 533219b2ee8SDavid du Colombier void 5349a747e4fSDavid du Colombier rauth(Job *job) 5353e12c5d1SDavid du Colombier { 5363ff48bf5SDavid du Colombier sendmsg(job, "dns: authentication not required"); 5377dd7cddfSDavid du Colombier } 5387dd7cddfSDavid du Colombier 5399a747e4fSDavid du Colombier /* 5409a747e4fSDavid du Colombier * don't flush till all the slaves are done 5419a747e4fSDavid du Colombier */ 5427dd7cddfSDavid du Colombier void 5437dd7cddfSDavid du Colombier rflush(Job *job) 5447dd7cddfSDavid du Colombier { 5457dd7cddfSDavid du Colombier flushjob(job->request.oldtag); 5467dd7cddfSDavid du Colombier sendmsg(job, 0); 5473e12c5d1SDavid du Colombier } 5483e12c5d1SDavid du Colombier 5493e12c5d1SDavid du Colombier void 5507dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf) 5513e12c5d1SDavid du Colombier { 5529a747e4fSDavid du Colombier if(mf->user != nil) 5539a747e4fSDavid du Colombier free(mf->user); 5549a747e4fSDavid du Colombier mf->user = estrdup(job->request.uname); 5553e12c5d1SDavid du Colombier mf->qid.vers = vers++; 5569a747e4fSDavid du Colombier mf->qid.type = QTDIR; 5579a747e4fSDavid du Colombier mf->qid.path = 0LL; 5587dd7cddfSDavid du Colombier job->reply.qid = mf->qid; 5597dd7cddfSDavid du Colombier sendmsg(job, 0); 5603e12c5d1SDavid du Colombier } 5613e12c5d1SDavid du Colombier 5623e12c5d1SDavid du Colombier char* 5637dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf) 5643e12c5d1SDavid du Colombier { 5654f8f669cSDavid du Colombier int i, nelems; 5663e12c5d1SDavid du Colombier char *err; 5679a747e4fSDavid du Colombier char **elems; 5689a747e4fSDavid du Colombier Mfile *nmf; 5699a747e4fSDavid du Colombier Qid qid; 5703e12c5d1SDavid du Colombier 5713e12c5d1SDavid du Colombier err = 0; 5729a747e4fSDavid du Colombier nmf = nil; 5739a747e4fSDavid du Colombier elems = job->request.wname; 5749a747e4fSDavid du Colombier nelems = job->request.nwname; 5759a747e4fSDavid du Colombier job->reply.nwqid = 0; 5769a747e4fSDavid du Colombier 5779a747e4fSDavid du Colombier if(job->request.newfid != job->request.fid){ 5789a747e4fSDavid du Colombier /* clone fid */ 5799a747e4fSDavid du Colombier nmf = copyfid(mf, job->request.newfid); 5809a747e4fSDavid du Colombier if(nmf == nil){ 5819a747e4fSDavid du Colombier err = "clone bad newfid"; 5829a747e4fSDavid du Colombier goto send; 5839a747e4fSDavid du Colombier } 5849a747e4fSDavid du Colombier mf = nmf; 5859a747e4fSDavid du Colombier } 5869a747e4fSDavid du Colombier /* else nmf will be nil */ 5879a747e4fSDavid du Colombier 5889a747e4fSDavid du Colombier qid = mf->qid; 5894f8f669cSDavid du Colombier if(nelems > 0) 5909a747e4fSDavid du Colombier /* walk fid */ 5919a747e4fSDavid du Colombier for(i=0; i<nelems && i<MAXWELEM; i++){ 5929a747e4fSDavid du Colombier if((qid.type & QTDIR) == 0){ 5933e12c5d1SDavid du Colombier err = "not a directory"; 5949a747e4fSDavid du Colombier break; 5953e12c5d1SDavid du Colombier } 5964f8f669cSDavid du Colombier if (strcmp(elems[i], "..") == 0 || 5974f8f669cSDavid du Colombier strcmp(elems[i], ".") == 0){ 5989a747e4fSDavid du Colombier qid.type = QTDIR; 5999a747e4fSDavid du Colombier qid.path = Qdir; 6009a747e4fSDavid du Colombier Found: 6019a747e4fSDavid du Colombier job->reply.wqid[i] = qid; 6029a747e4fSDavid du Colombier job->reply.nwqid++; 6039a747e4fSDavid du Colombier continue; 6043e12c5d1SDavid du Colombier } 6059a747e4fSDavid du Colombier if(strcmp(elems[i], "dns") == 0){ 6069a747e4fSDavid du Colombier qid.type = QTFILE; 6079a747e4fSDavid du Colombier qid.path = Qdns; 6089a747e4fSDavid du Colombier goto Found; 6093e12c5d1SDavid du Colombier } 6109a747e4fSDavid du Colombier err = "file does not exist"; 6119a747e4fSDavid du Colombier break; 6129a747e4fSDavid du Colombier } 6139a747e4fSDavid du Colombier 6143e12c5d1SDavid du Colombier send: 6159a747e4fSDavid du Colombier if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)) 6169a747e4fSDavid du Colombier freefid(nmf); 6179a747e4fSDavid du Colombier if(err == nil) 6189a747e4fSDavid du Colombier mf->qid = qid; 6197dd7cddfSDavid du Colombier sendmsg(job, err); 6203e12c5d1SDavid du Colombier return err; 6213e12c5d1SDavid du Colombier } 6223e12c5d1SDavid du Colombier 6233e12c5d1SDavid du Colombier void 6247dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf) 6253e12c5d1SDavid du Colombier { 6263e12c5d1SDavid du Colombier int mode; 6273e12c5d1SDavid du Colombier char *err; 6283e12c5d1SDavid du Colombier 6293e12c5d1SDavid du Colombier err = 0; 6307dd7cddfSDavid du Colombier mode = job->request.mode; 6314f8f669cSDavid du Colombier if(mf->qid.type & QTDIR) 6323e12c5d1SDavid du Colombier if(mode) 6333e12c5d1SDavid du Colombier err = "permission denied"; 6347dd7cddfSDavid du Colombier job->reply.qid = mf->qid; 6359a747e4fSDavid du Colombier job->reply.iounit = 0; 6367dd7cddfSDavid du Colombier sendmsg(job, err); 6373e12c5d1SDavid du Colombier } 6383e12c5d1SDavid du Colombier 6393e12c5d1SDavid du Colombier void 6407dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf) 6413e12c5d1SDavid du Colombier { 6423e12c5d1SDavid du Colombier USED(mf); 6437dd7cddfSDavid du Colombier sendmsg(job, "creation permission denied"); 6443e12c5d1SDavid du Colombier } 6453e12c5d1SDavid du Colombier 6463e12c5d1SDavid du Colombier void 6477dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf) 6483e12c5d1SDavid du Colombier { 6494f8f669cSDavid du Colombier int i, n; 6506b0d5c8bSDavid du Colombier long clock; 6514f8f669cSDavid du Colombier ulong cnt; 6524f8f669cSDavid du Colombier vlong off; 6534f8f669cSDavid du Colombier char *err; 654254fe3d3SDavid du Colombier uchar buf[Maxfdata]; 6554f8f669cSDavid du Colombier Dir dir; 6563e12c5d1SDavid du Colombier 6573e12c5d1SDavid du Colombier n = 0; 6584f8f669cSDavid du Colombier err = nil; 6597dd7cddfSDavid du Colombier off = job->request.offset; 6607dd7cddfSDavid du Colombier cnt = job->request.count; 6614f8f669cSDavid du Colombier *buf = '\0'; 6624f8f669cSDavid du Colombier job->reply.data = (char*)buf; 6639a747e4fSDavid du Colombier if(mf->qid.type & QTDIR){ 6644f8f669cSDavid du Colombier clock = time(nil); 6653e12c5d1SDavid du Colombier if(off == 0){ 6666aaebd7dSDavid du Colombier memset(&dir, 0, sizeof dir); 6679a747e4fSDavid du Colombier dir.name = "dns"; 6689a747e4fSDavid du Colombier dir.qid.type = QTFILE; 6693e12c5d1SDavid du Colombier dir.qid.vers = vers; 6703e12c5d1SDavid du Colombier dir.qid.path = Qdns; 6713e12c5d1SDavid du Colombier dir.mode = 0666; 6723e12c5d1SDavid du Colombier dir.length = 0; 6734f8f669cSDavid du Colombier dir.uid = dir.gid = dir.muid = mf->user; 6744f8f669cSDavid du Colombier dir.atime = dir.mtime = clock; /* wrong */ 6759a747e4fSDavid du Colombier n = convD2M(&dir, buf, sizeof buf); 6763e12c5d1SDavid du Colombier } 6774f8f669cSDavid du Colombier } else if (off < 0) 6784f8f669cSDavid du Colombier err = "negative read offset"; 6794f8f669cSDavid du Colombier else { 6804f8f669cSDavid du Colombier /* first offset will always be zero */ 6817dd7cddfSDavid du Colombier for(i = 1; i <= mf->nrr; i++) 6827dd7cddfSDavid du Colombier if(mf->rr[i] > off) 6833e12c5d1SDavid du Colombier break; 6844f8f669cSDavid du Colombier if(i <= mf->nrr) { 6857dd7cddfSDavid du Colombier if(off + cnt > mf->rr[i]) 6867dd7cddfSDavid du Colombier n = mf->rr[i] - off; 6877dd7cddfSDavid du Colombier else 6887dd7cddfSDavid du Colombier n = cnt; 6894f8f669cSDavid du Colombier assert(n >= 0); 6907dd7cddfSDavid du Colombier job->reply.data = mf->reply + off; 6913e12c5d1SDavid du Colombier } 6924f8f669cSDavid du Colombier } 6937dd7cddfSDavid du Colombier job->reply.count = n; 6947dd7cddfSDavid du Colombier sendmsg(job, err); 6953e12c5d1SDavid du Colombier } 6963e12c5d1SDavid du Colombier 6973e12c5d1SDavid du Colombier void 6987dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf, Request *req) 6993e12c5d1SDavid du Colombier { 7004f8f669cSDavid du Colombier int rooted, status, wantsav; 7017dd7cddfSDavid du Colombier long n; 7024f8f669cSDavid du Colombier ulong cnt; 7037dd7cddfSDavid du Colombier char *err, *p, *atype; 7047dd7cddfSDavid du Colombier RR *rp, *tp, *neg; 7053e12c5d1SDavid du Colombier 7064f8f669cSDavid du Colombier err = nil; 7077dd7cddfSDavid du Colombier cnt = job->request.count; 7089a747e4fSDavid du Colombier if(mf->qid.type & QTDIR){ 7093e12c5d1SDavid du Colombier err = "can't write directory"; 7103e12c5d1SDavid du Colombier goto send; 7113e12c5d1SDavid du Colombier } 7124f8f669cSDavid du Colombier if (job->request.offset != 0) { 7134f8f669cSDavid du Colombier err = "writing at non-zero offset"; 7144f8f669cSDavid du Colombier goto send; 7154f8f669cSDavid du Colombier } 7163e12c5d1SDavid du Colombier if(cnt >= Maxrequest){ 7173e12c5d1SDavid du Colombier err = "request too long"; 7183e12c5d1SDavid du Colombier goto send; 7193e12c5d1SDavid du Colombier } 7207dd7cddfSDavid du Colombier job->request.data[cnt] = 0; 7217dd7cddfSDavid du Colombier if(cnt > 0 && job->request.data[cnt-1] == '\n') 7227dd7cddfSDavid du Colombier job->request.data[cnt-1] = 0; 7233e12c5d1SDavid du Colombier 7243e12c5d1SDavid du Colombier /* 7257dd7cddfSDavid du Colombier * special commands 726219b2ee8SDavid du Colombier */ 727410ea80bSDavid du Colombier // dnslog("rwrite got: %s", job->request.data); 7284f8f669cSDavid du Colombier if(strcmp(job->request.data, "debug")==0){ 729219b2ee8SDavid du Colombier debug ^= 1; 730219b2ee8SDavid du Colombier goto send; 7314f8f669cSDavid du Colombier } else if(strcmp(job->request.data, "dump")==0){ 732219b2ee8SDavid du Colombier dndump("/lib/ndb/dnsdump"); 733219b2ee8SDavid du Colombier goto send; 7344f8f669cSDavid du Colombier } else if(strcmp(job->request.data, "poolcheck")==0){ 7359a747e4fSDavid du Colombier poolcheck(mainmem); 7369a747e4fSDavid du Colombier goto send; 7374f927735SDavid du Colombier } else if(strcmp(job->request.data, "refresh")==0){ 7384f927735SDavid du Colombier needrefresh = 1; 7394f927735SDavid du Colombier goto send; 740c73252aeSDavid du Colombier } else if(strcmp(job->request.data, "restart")==0){ 741c73252aeSDavid du Colombier stop = 1; 742c73252aeSDavid du Colombier goto send; 7434f927735SDavid du Colombier } else if(strcmp(job->request.data, "stats")==0){ 7444f927735SDavid du Colombier dnstats("/lib/ndb/dnsstats"); 7454f927735SDavid du Colombier goto send; 746f2714ceaSDavid du Colombier } else if(strncmp(job->request.data, "target ", 7)==0){ 747f2714ceaSDavid du Colombier target = atol(job->request.data + 7); 74821abd8f2SDavid du Colombier dnslog("target set to %ld", target); 74921abd8f2SDavid du Colombier goto send; 75021abd8f2SDavid du Colombier } else if(strcmp(job->request.data, "age")==0){ 75121abd8f2SDavid du Colombier dnslog("dump, age & dump forced"); 75221abd8f2SDavid du Colombier dndump("/lib/ndb/dnsdump1"); 75321abd8f2SDavid du Colombier dnforceage(); 75421abd8f2SDavid du Colombier dndump("/lib/ndb/dnsdump2"); 75521abd8f2SDavid du Colombier goto send; 756219b2ee8SDavid du Colombier } 757219b2ee8SDavid du Colombier 758219b2ee8SDavid du Colombier /* 7597dd7cddfSDavid du Colombier * kill previous reply 7607dd7cddfSDavid du Colombier */ 7617dd7cddfSDavid du Colombier mf->nrr = 0; 7627dd7cddfSDavid du Colombier mf->rr[0] = 0; 7637dd7cddfSDavid du Colombier 7647dd7cddfSDavid du Colombier /* 7653e12c5d1SDavid du Colombier * break up request (into a name and a type) 7663e12c5d1SDavid du Colombier */ 7677dd7cddfSDavid du Colombier atype = strchr(job->request.data, ' '); 7683e12c5d1SDavid du Colombier if(atype == 0){ 7693e12c5d1SDavid du Colombier err = "illegal request"; 7703e12c5d1SDavid du Colombier goto send; 7713e12c5d1SDavid du Colombier } else 7723e12c5d1SDavid du Colombier *atype++ = 0; 7733e12c5d1SDavid du Colombier 7747dd7cddfSDavid du Colombier /* 7757dd7cddfSDavid du Colombier * tracing request 7767dd7cddfSDavid du Colombier */ 7777dd7cddfSDavid du Colombier if(strcmp(atype, "trace") == 0){ 7787dd7cddfSDavid du Colombier if(trace) 7797dd7cddfSDavid du Colombier free(trace); 7807dd7cddfSDavid du Colombier if(*job->request.data) 7819a747e4fSDavid du Colombier trace = estrdup(job->request.data); 7827dd7cddfSDavid du Colombier else 7837dd7cddfSDavid du Colombier trace = 0; 7847dd7cddfSDavid du Colombier goto send; 7857dd7cddfSDavid du Colombier } 7867dd7cddfSDavid du Colombier 7874f8f669cSDavid du Colombier /* normal request: domain [type] */ 788a41547ffSDavid du Colombier stats.qrecvd9p++; 7893e12c5d1SDavid du Colombier mf->type = rrtype(atype); 7903e12c5d1SDavid du Colombier if(mf->type < 0){ 7913e12c5d1SDavid du Colombier err = "unknown type"; 7923e12c5d1SDavid du Colombier goto send; 7933e12c5d1SDavid du Colombier } 7943e12c5d1SDavid du Colombier 7957dd7cddfSDavid du Colombier p = atype - 2; 7967dd7cddfSDavid du Colombier if(p >= job->request.data && *p == '.'){ 7977dd7cddfSDavid du Colombier rooted = 1; 7987dd7cddfSDavid du Colombier *p = 0; 7997dd7cddfSDavid du Colombier } else 8007dd7cddfSDavid du Colombier rooted = 0; 8013e12c5d1SDavid du Colombier 8027dd7cddfSDavid du Colombier p = job->request.data; 8037dd7cddfSDavid du Colombier if(*p == '!'){ 8047dd7cddfSDavid du Colombier wantsav = 1; 8057dd7cddfSDavid du Colombier p++; 8067dd7cddfSDavid du Colombier } else 8077dd7cddfSDavid du Colombier wantsav = 0; 8084f8f669cSDavid du Colombier 8099a747e4fSDavid du Colombier dncheck(0, 1); 8104f8f669cSDavid du Colombier status = 0; 8117dd7cddfSDavid du Colombier rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status); 8124f8f669cSDavid du Colombier 8139a747e4fSDavid du Colombier dncheck(0, 1); 814*530fef66SDavid du Colombier lock(&dnlock); 8157dd7cddfSDavid du Colombier neg = rrremneg(&rp); 8167dd7cddfSDavid du Colombier if(neg){ 8177dd7cddfSDavid du Colombier status = neg->negrcode; 8187dd7cddfSDavid du Colombier rrfreelist(neg); 8197dd7cddfSDavid du Colombier } 820*530fef66SDavid du Colombier unlock(&dnlock); 8214f8f669cSDavid du Colombier 8224f8f669cSDavid du Colombier if(rp == nil) 823271b8d73SDavid du Colombier switch(status){ 824271b8d73SDavid du Colombier case Rname: 8257dd7cddfSDavid du Colombier err = "name does not exist"; 826271b8d73SDavid du Colombier break; 827271b8d73SDavid du Colombier case Rserver: 828271b8d73SDavid du Colombier err = "dns failure"; 829271b8d73SDavid du Colombier break; 830271b8d73SDavid du Colombier default: 831271b8d73SDavid du Colombier err = "resource does not exist"; 832271b8d73SDavid du Colombier break; 833271b8d73SDavid du Colombier } 8344f8f669cSDavid du Colombier else { 83534f77ae3SDavid du Colombier lock(&joblock); 83634f77ae3SDavid du Colombier if(!job->flushed){ 8377dd7cddfSDavid du Colombier /* format data to be read later */ 8387dd7cddfSDavid du Colombier n = 0; 8397dd7cddfSDavid du Colombier mf->nrr = 0; 8407dd7cddfSDavid du Colombier for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp && 8417dd7cddfSDavid du Colombier tsame(mf->type, tp->type); tp = tp->next){ 8427dd7cddfSDavid du Colombier mf->rr[mf->nrr++] = n; 8437dd7cddfSDavid du Colombier if(wantsav) 8444f8f669cSDavid du Colombier n += snprint(mf->reply+n, Maxreply-n, 8454f8f669cSDavid du Colombier "%Q", tp); 8467dd7cddfSDavid du Colombier else 8474f8f669cSDavid du Colombier n += snprint(mf->reply+n, Maxreply-n, 8484f8f669cSDavid du Colombier "%R", tp); 8497dd7cddfSDavid du Colombier } 8507dd7cddfSDavid du Colombier mf->rr[mf->nrr] = n; 85134f77ae3SDavid du Colombier } 85234f77ae3SDavid du Colombier unlock(&joblock); 8537dd7cddfSDavid du Colombier rrfreelist(rp); 8547dd7cddfSDavid du Colombier } 8553e12c5d1SDavid du Colombier send: 8569a747e4fSDavid du Colombier dncheck(0, 1); 8577dd7cddfSDavid du Colombier job->reply.count = cnt; 8587dd7cddfSDavid du Colombier sendmsg(job, err); 8593e12c5d1SDavid du Colombier } 8603e12c5d1SDavid du Colombier 8613e12c5d1SDavid du Colombier void 8627dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf) 8633e12c5d1SDavid du Colombier { 8647dd7cddfSDavid du Colombier freefid(mf); 8657dd7cddfSDavid du Colombier sendmsg(job, 0); 8663e12c5d1SDavid du Colombier } 8673e12c5d1SDavid du Colombier 8683e12c5d1SDavid du Colombier void 8697dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf) 8703e12c5d1SDavid du Colombier { 8713e12c5d1SDavid du Colombier USED(mf); 8727dd7cddfSDavid du Colombier sendmsg(job, "remove permission denied"); 8733e12c5d1SDavid du Colombier } 8743e12c5d1SDavid du Colombier 8753e12c5d1SDavid du Colombier void 8767dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf) 8773e12c5d1SDavid du Colombier { 8783e12c5d1SDavid du Colombier Dir dir; 8799a747e4fSDavid du Colombier uchar buf[IOHDRSZ+Maxfdata]; 8803e12c5d1SDavid du Colombier 8816aaebd7dSDavid du Colombier memset(&dir, 0, sizeof dir); 8829a747e4fSDavid du Colombier if(mf->qid.type & QTDIR){ 8839a747e4fSDavid du Colombier dir.name = "."; 8849a747e4fSDavid du Colombier dir.mode = DMDIR|0555; 885219b2ee8SDavid du Colombier } else { 8869a747e4fSDavid du Colombier dir.name = "dns"; 8873e12c5d1SDavid du Colombier dir.mode = 0666; 888219b2ee8SDavid du Colombier } 889219b2ee8SDavid du Colombier dir.qid = mf->qid; 8903e12c5d1SDavid du Colombier dir.length = 0; 8914f8f669cSDavid du Colombier dir.uid = dir.gid = dir.muid = mf->user; 8924f8f669cSDavid du Colombier dir.atime = dir.mtime = time(nil); 8939a747e4fSDavid du Colombier job->reply.nstat = convD2M(&dir, buf, sizeof buf); 8949a747e4fSDavid du Colombier job->reply.stat = buf; 8957dd7cddfSDavid du Colombier sendmsg(job, 0); 8963e12c5d1SDavid du Colombier } 8973e12c5d1SDavid du Colombier 8983e12c5d1SDavid du Colombier void 8997dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf) 9003e12c5d1SDavid du Colombier { 9013e12c5d1SDavid du Colombier USED(mf); 9027dd7cddfSDavid du Colombier sendmsg(job, "wstat permission denied"); 9033e12c5d1SDavid du Colombier } 9043e12c5d1SDavid du Colombier 9053e12c5d1SDavid du Colombier void 9067dd7cddfSDavid du Colombier sendmsg(Job *job, char *err) 9073e12c5d1SDavid du Colombier { 9083e12c5d1SDavid du Colombier int n; 9099a747e4fSDavid du Colombier uchar mdata[IOHDRSZ + Maxfdata]; 9109a747e4fSDavid du Colombier char ename[ERRMAX]; 9113e12c5d1SDavid du Colombier 9123e12c5d1SDavid du Colombier if(err){ 9137dd7cddfSDavid du Colombier job->reply.type = Rerror; 9144f8f669cSDavid du Colombier snprint(ename, sizeof ename, "dns: %s", err); 9159a747e4fSDavid du Colombier job->reply.ename = ename; 9164f8f669cSDavid du Colombier }else 9177dd7cddfSDavid du Colombier job->reply.type = job->request.type+1; 9187dd7cddfSDavid du Colombier job->reply.tag = job->request.tag; 9199a747e4fSDavid du Colombier n = convS2M(&job->reply, mdata, sizeof mdata); 9209a747e4fSDavid du Colombier if(n == 0){ 9214f8f669cSDavid du Colombier warning("sendmsg convS2M of %F returns 0", &job->reply); 9229a747e4fSDavid du Colombier abort(); 9233e12c5d1SDavid du Colombier } 9249a747e4fSDavid du Colombier lock(&joblock); 9259a747e4fSDavid du Colombier if(job->flushed == 0) 9269a747e4fSDavid du Colombier if(write(mfd[1], mdata, n)!=n) 9279a747e4fSDavid du Colombier sysfatal("mount write"); 9287dd7cddfSDavid du Colombier unlock(&joblock); 9299a747e4fSDavid du Colombier if(debug) 9304f8f669cSDavid du Colombier dnslog("%F %d", &job->reply, n); 9313e12c5d1SDavid du Colombier } 9323e12c5d1SDavid du Colombier 9333e12c5d1SDavid du Colombier /* 9347dd7cddfSDavid du Colombier * the following varies between dnsdebug and dns 9353e12c5d1SDavid du Colombier */ 9363e12c5d1SDavid du Colombier void 9377dd7cddfSDavid du Colombier logreply(int id, uchar *addr, DNSmsg *mp) 9383e12c5d1SDavid du Colombier { 9397dd7cddfSDavid du Colombier RR *rp; 9403e12c5d1SDavid du Colombier 9414f8f669cSDavid du Colombier dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr, 9427dd7cddfSDavid du Colombier mp->flags & Fauth? " auth": "", 9437dd7cddfSDavid du Colombier mp->flags & Ftrunc? " trunc": "", 9447dd7cddfSDavid du Colombier mp->flags & Frecurse? " rd": "", 9457dd7cddfSDavid du Colombier mp->flags & Fcanrec? " ra": "", 9464f8f669cSDavid du Colombier (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": ""); 9477dd7cddfSDavid du Colombier for(rp = mp->qd; rp != nil; rp = rp->next) 9484f8f669cSDavid du Colombier dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name); 9497dd7cddfSDavid du Colombier for(rp = mp->an; rp != nil; rp = rp->next) 9504f8f669cSDavid du Colombier dnslog("%d: rcvd %I an %R", id, addr, rp); 9517dd7cddfSDavid du Colombier for(rp = mp->ns; rp != nil; rp = rp->next) 9524f8f669cSDavid du Colombier dnslog("%d: rcvd %I ns %R", id, addr, rp); 9537dd7cddfSDavid du Colombier for(rp = mp->ar; rp != nil; rp = rp->next) 9544f8f669cSDavid du Colombier dnslog("%d: rcvd %I ar %R", id, addr, rp); 9553e12c5d1SDavid du Colombier } 9567dd7cddfSDavid du Colombier 9577dd7cddfSDavid du Colombier void 9587dd7cddfSDavid du Colombier logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) 9597dd7cddfSDavid du Colombier { 9607dd7cddfSDavid du Colombier char buf[12]; 9617dd7cddfSDavid du Colombier 9624f8f669cSDavid du Colombier dnslog("[%d] %d.%d: sending to %I/%s %s %s", 9634f8f669cSDavid du Colombier getpid(), id, subid, addr, sname, rname, 9644f8f669cSDavid du Colombier rrname(type, buf, sizeof buf)); 9657dd7cddfSDavid du Colombier } 9667dd7cddfSDavid du Colombier 9677dd7cddfSDavid du Colombier RR* 9687dd7cddfSDavid du Colombier getdnsservers(int class) 9697dd7cddfSDavid du Colombier { 9707dd7cddfSDavid du Colombier return dnsservers(class); 9713e12c5d1SDavid du Colombier } 972