1 #include "all.h" 2 #include <ndb.h> 3 #include <ip.h> 4 5 static int alarmflag; 6 7 static int Iconv(Fmt*); 8 static void openudp(int); 9 static void cachereply(Rpccall*, void*, int); 10 static int replycache(int, Rpccall*, long (*)(int, void*, long)); 11 static void udpserver(int, Progmap*); 12 static void tcpserver(int, Progmap*); 13 static void getendpoints(Udphdr*, char*); 14 static long readtcp(int, void*, long); 15 static long writetcp(int, void*, long); 16 static int servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long), 17 int, Progmap*); 18 void (*rpcalarm)(void); 19 int rpcdebug; 20 int rejectall; 21 int p9debug; 22 23 int nocache; 24 25 uchar buf[9000]; 26 uchar rbuf[9000]; 27 uchar resultbuf[9000]; 28 29 void 30 server(int argc, char **argv, int myport, Progmap *progmap) 31 { 32 int Argc=argc; char **Argv=argv; 33 int tcp = 0; 34 Progmap *pg; 35 36 fmtinstall('I', Iconv); 37 fmtinstall('F', fcallfmt); 38 fmtinstall('D', dirfmt); 39 40 switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){ 41 case -1: 42 panic("fork"); 43 default: 44 _exits(0); 45 case 0: 46 break; 47 } 48 ARGBEGIN{ 49 case '9': 50 ++p9debug; 51 break; 52 case 'r': 53 ++rejectall; 54 break; 55 case 'v': 56 ++chatty; 57 break; 58 case 'D': 59 ++rpcdebug; 60 break; 61 case 'C': 62 ++nocache; 63 break; 64 case 't': 65 tcp = 1; 66 break; 67 }ARGEND 68 69 switch(rfork(RFMEM|RFPROC)){ 70 case 0: 71 for(;;){ 72 sleep(30*1000); 73 alarmflag = 1; 74 } 75 case -1: 76 sysfatal("rfork: %r"); 77 } 78 79 for(pg=progmap; pg->init; pg++) 80 (*pg->init)(Argc, Argv); 81 if(tcp) 82 tcpserver(myport, progmap); 83 else 84 udpserver(myport, progmap); 85 } 86 87 static void 88 udpserver(int myport, Progmap *progmap) 89 { 90 char service[128]; 91 char data[128]; 92 char devdir[40]; 93 int ctlfd, datafd; 94 95 snprint(service, sizeof service, "udp!*!%d", myport); 96 ctlfd = announce(service, devdir); 97 if(ctlfd < 0) 98 panic("can't announce %s: %r\n", service); 99 if(fprint(ctlfd, "headers") < 0) 100 panic("can't set header mode: %r\n"); 101 102 snprint(data, sizeof data, "%s/data", devdir); 103 104 datafd = open(data, ORDWR); 105 if(datafd < 0) 106 panic("can't open udp data: %r\n"); 107 close(ctlfd); 108 109 chatsrv(0); 110 clog("%s: listening to port %d\n", argv0, myport); 111 for(;;){ 112 if(servemsg(datafd, read, write, myport, progmap) < 0) 113 break; 114 } 115 exits(0); 116 } 117 118 static void 119 tcpserver(int myport, Progmap *progmap) 120 { 121 char adir[40]; 122 char ldir[40]; 123 char ds[40]; 124 int actl, lctl, data; 125 126 snprint(ds, sizeof ds, "tcp!*!%d", myport); 127 chatsrv(0); 128 actl = -1; 129 for(;;){ 130 if(actl < 0){ 131 actl = announce(ds, adir); 132 if(actl < 0){ 133 clog("%s: listening to tcp port %d\n", argv0, myport); 134 clog("announcing: %r"); 135 break; 136 } 137 } 138 lctl = listen(adir, ldir); 139 if(lctl < 0){ 140 close(actl); 141 actl = -1; 142 continue; 143 } 144 switch(fork()){ 145 case -1: 146 clog("%s!%d: %r\n", argv0, myport); 147 /* fall through */ 148 default: 149 close(lctl); 150 continue; 151 case 0: 152 close(actl); 153 data = accept(lctl, ldir); 154 close(lctl); 155 if(data < 0) 156 exits(0); 157 158 getendpoints((Udphdr*)buf, ldir); 159 160 for(;;){ 161 if(servemsg(data, readtcp, writetcp, myport, progmap) < 0) 162 break; 163 } 164 close(data); 165 exits(0); 166 } 167 } 168 exits(0); 169 } 170 171 static int 172 servemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long), 173 int myport, Progmap * progmap) 174 { 175 int i, n, nreply; 176 Rpccall rcall, rreply; 177 int vlo, vhi; 178 Progmap *pg; 179 Procmap *pp; 180 char errbuf[ERRMAX]; 181 182 if(alarmflag){ 183 alarmflag = 0; 184 if(rpcalarm) 185 (*rpcalarm)(); 186 } 187 n = (*readmsg)(fd, buf, sizeof buf); 188 if(n < 0){ 189 errstr(errbuf, sizeof errbuf); 190 if(strcmp(errbuf, "interrupted") == 0) 191 return 0; 192 clog("port %d: error: %s\n", myport, errbuf); 193 return -1; 194 } 195 if(n == 0){ 196 clog("port %d: EOF\n", myport); 197 return -1; 198 } 199 if(rpcdebug == 1) 200 fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n", 201 argv0, buf[12], buf[13], buf[14], buf[15], 202 (buf[32]<<8)|buf[33]); 203 i = rpcM2S(buf, &rcall, n); 204 if(i != 0){ 205 clog("udp port %d: message format error %d\n", 206 myport, i); 207 return 0; 208 } 209 if(rpcdebug > 1) 210 rpcprint(2, &rcall); 211 if(rcall.mtype != CALL) 212 return 0; 213 if(replycache(fd, &rcall, writemsg)) 214 return 0; 215 nreply = 0; 216 rreply.host = rcall.host; 217 rreply.port = rcall.port; 218 rreply.lhost = rcall.lhost; 219 rreply.lport = rcall.lport; 220 rreply.xid = rcall.xid; 221 rreply.mtype = REPLY; 222 if(rcall.rpcvers != 2){ 223 rreply.stat = MSG_DENIED; 224 rreply.rstat = RPC_MISMATCH; 225 rreply.rlow = 2; 226 rreply.rhigh = 2; 227 goto send_reply; 228 } 229 if(rejectall){ 230 rreply.stat = MSG_DENIED; 231 rreply.rstat = AUTH_ERROR; 232 rreply.authstat = AUTH_TOOWEAK; 233 goto send_reply; 234 } 235 i = n - (((uchar *)rcall.args) - buf); 236 if(rpcdebug > 1) 237 fprint(2, "arg size = %d\n", i); 238 rreply.stat = MSG_ACCEPTED; 239 rreply.averf.flavor = 0; 240 rreply.averf.count = 0; 241 rreply.results = resultbuf; 242 vlo = 0x7fffffff; 243 vhi = -1; 244 for(pg=progmap; pg->pmap; pg++){ 245 if(pg->progno != rcall.prog) 246 continue; 247 if(pg->vers == rcall.vers) 248 break; 249 if(pg->vers < vlo) 250 vlo = pg->vers; 251 if(pg->vers > vhi) 252 vhi = pg->vers; 253 } 254 if(pg->pmap == 0){ 255 if(vhi < 0) 256 rreply.astat = PROG_UNAVAIL; 257 else{ 258 rreply.astat = PROG_MISMATCH; 259 rreply.plow = vlo; 260 rreply.phigh = vhi; 261 } 262 goto send_reply; 263 } 264 for(pp = pg->pmap; pp->procp; pp++) 265 if(rcall.proc == pp->procno){ 266 if(rpcdebug > 1) 267 fprint(2, "process %d\n", pp->procno); 268 rreply.astat = SUCCESS; 269 nreply = (*pp->procp)(i, &rcall, &rreply); 270 goto send_reply; 271 } 272 rreply.astat = PROC_UNAVAIL; 273 send_reply: 274 if(nreply >= 0){ 275 i = rpcS2M(&rreply, nreply, rbuf); 276 if(rpcdebug > 1) 277 rpcprint(2, &rreply); 278 (*writemsg)(fd, rbuf, i); 279 cachereply(&rreply, rbuf, i); 280 } 281 return 0; 282 } 283 284 static void 285 getendpoint(char *dir, char *file, uchar *addr, uchar *port) 286 { 287 int fd, n; 288 char buf[128]; 289 char *sys, *serv; 290 291 sys = serv = 0; 292 293 snprint(buf, sizeof buf, "%s/%s", dir, file); 294 fd = open(buf, OREAD); 295 if(fd >= 0){ 296 n = read(fd, buf, sizeof(buf)-1); 297 if(n>0){ 298 buf[n-1] = 0; 299 serv = strchr(buf, '!'); 300 if(serv){ 301 *serv++ = 0; 302 serv = strdup(serv); 303 } 304 sys = strdup(buf); 305 } 306 close(fd); 307 } 308 if(serv == 0) 309 serv = strdup("unknown"); 310 if(sys == 0) 311 sys = strdup("unknown"); 312 parseip(addr, sys); 313 n = atoi(serv); 314 hnputs(port, n); 315 } 316 317 static void 318 getendpoints(Udphdr *ep, char *dir) 319 { 320 getendpoint(dir, "local", ep->laddr, ep->lport); 321 getendpoint(dir, "remote", ep->raddr, ep->rport); 322 } 323 324 static long 325 readtcp(int fd, void *vbuf, long blen) 326 { 327 uchar mk[4]; 328 int n, m, sofar; 329 ulong done; 330 char *buf; 331 332 buf = vbuf; 333 buf += Udphdrsize; 334 blen -= Udphdrsize; 335 336 done = 0; 337 for(sofar = 0; !done; sofar += n){ 338 m = readn(fd, mk, 4); 339 if(m < 4) 340 return 0; 341 done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3]; 342 m = done & 0x7fffffff; 343 done &= 0x80000000; 344 if(m > blen-sofar) 345 return -1; 346 n = readn(fd, buf+sofar, m); 347 if(m != n) 348 return 0; 349 } 350 return sofar + Udphdrsize; 351 } 352 353 static long 354 writetcp(int fd, void *vbuf, long len) 355 { 356 char *buf; 357 358 buf = vbuf; 359 buf += Udphdrsize; 360 len -= Udphdrsize; 361 362 buf -= 4; 363 buf[0] = 0x80 | (len>>24); 364 buf[1] = len>>16; 365 buf[2] = len>>8; 366 buf[3] = len; 367 len += 4; 368 return write(fd, buf, len); 369 } 370 /* 371 *long 372 *niwrite(int fd, void *buf, long count) 373 *{ 374 * char errbuf[ERRLEN]; 375 * long n; 376 * 377 * for(;;){ 378 * n = write(fd, buf, count); 379 * if(n < 0){ 380 * errstr(errbuf); 381 * if(strcmp(errbuf, "interrupted") == 0) 382 * continue; 383 * clog("niwrite error: %s\n", errbuf); 384 * werrstr(errbuf); 385 * } 386 * break; 387 * } 388 * return n; 389 *} 390 */ 391 long 392 niwrite(int fd, void *buf, long n) 393 { 394 // int savalarm; 395 396 // savalarm = alarm(0); 397 n = write(fd, buf, n); 398 // if(savalarm > 0) 399 // alarm(savalarm); 400 return n; 401 } 402 403 typedef struct Namecache Namecache; 404 struct Namecache { 405 char dom[256]; 406 ulong ipaddr; 407 Namecache *next; 408 }; 409 410 Namecache *dnscache; 411 412 static Namecache* 413 domlookupl(void *name, int len) 414 { 415 Namecache *n, **ln; 416 417 if(len >= sizeof(n->dom)) 418 return nil; 419 420 for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) { 421 if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) { 422 *ln = n->next; 423 n->next = dnscache; 424 dnscache = n; 425 return n; 426 } 427 } 428 return nil; 429 } 430 431 static Namecache* 432 domlookup(void *name) 433 { 434 return domlookupl(name, strlen(name)); 435 } 436 437 static Namecache* 438 iplookup(ulong ip) 439 { 440 Namecache *n, **ln; 441 442 for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) { 443 if(n->ipaddr == ip) { 444 *ln = n->next; 445 n->next = dnscache; 446 dnscache = n; 447 return n; 448 } 449 } 450 return nil; 451 } 452 453 static Namecache* 454 addcacheentry(void *name, int len, ulong ip) 455 { 456 Namecache *n; 457 458 if(len >= sizeof(n->dom)) 459 return nil; 460 461 n = malloc(sizeof(*n)); 462 if(n == nil) 463 return nil; 464 strncpy(n->dom, name, len); 465 n->dom[len] = 0; 466 n->ipaddr = ip; 467 n->next = dnscache; 468 dnscache = n; 469 return nil; 470 } 471 472 int 473 getdnsdom(ulong ip, char *name, int len) 474 { 475 char buf[Ndbvlen]; 476 char dom[Ndbvlen]; 477 Namecache *nc; 478 Ndbtuple *t; 479 480 if(nc=iplookup(ip)) { 481 strncpy(name, nc->dom, len); 482 name[len-1] = 0; 483 return 0; 484 } 485 clog("getdnsdom: %I\n", ip); 486 snprint(buf, sizeof buf, "%I", ip); 487 t = csgetval("/net", "ip", buf, "dom", dom); 488 clog("csgetval %p\n", t); 489 if(t == nil) 490 return -1; 491 ndbfree(t); 492 clog("csgetval %s\n", dom); 493 strncpy(name, dom, len-1); 494 name[len] = 0; 495 addcacheentry(name, strlen(name), ip); 496 return 0; 497 } 498 499 int 500 getdom(ulong ip, char *dom, int len) 501 { 502 int i; 503 static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 }; 504 char **pr; 505 506 if(getdnsdom(ip, dom, len)<0) 507 return -1; 508 509 for(pr=prefix; *pr; pr++){ 510 i = strlen(*pr); 511 if(strncmp(dom, *pr, i) == 0) { 512 memmove(dom, dom+i, len-i); 513 break; 514 } 515 } 516 return 0; 517 } 518 519 #define MAXCACHE 64 520 521 static Rpccache *head, *tail; 522 static int ncache; 523 524 static void 525 cachereply(Rpccall *rp, void *buf, int len) 526 { 527 Rpccache *cp; 528 529 if(nocache) 530 return; 531 532 if(ncache >= MAXCACHE){ 533 if(rpcdebug) 534 fprint(2, "%s: drop %I/%ld, xid %uld, len %d\n", 535 argv0, tail->host, 536 tail->port, tail->xid, tail->n); 537 tail = tail->prev; 538 free(tail->next); 539 tail->next = 0; 540 --ncache; 541 } 542 cp = malloc(sizeof(Rpccache)+len-4); 543 if(cp == 0){ 544 clog("cachereply: malloc %d failed\n", len); 545 return; 546 } 547 ++ncache; 548 cp->prev = 0; 549 cp->next = head; 550 if(head) 551 head->prev = cp; 552 else 553 tail = cp; 554 head = cp; 555 cp->host = rp->host; 556 cp->port = rp->port; 557 cp->xid = rp->xid; 558 cp->n = len; 559 memmove(cp->data, buf, len); 560 if(rpcdebug) 561 fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n", 562 argv0, cp->host, cp->port, cp->xid, cp->n); 563 } 564 565 static int 566 replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long)) 567 { 568 Rpccache *cp; 569 570 for(cp=head; cp; cp=cp->next) 571 if(cp->host == rp->host && 572 cp->port == rp->port && 573 cp->xid == rp->xid) 574 break; 575 if(cp == 0) 576 return 0; 577 if(cp->prev){ /* move to front */ 578 cp->prev->next = cp->next; 579 if(cp->next) 580 cp->next->prev = cp->prev; 581 else 582 tail = cp->prev; 583 cp->prev = 0; 584 cp->next = head; 585 head->prev = cp; 586 head = cp; 587 } 588 (*writemsg)(fd, cp->data, cp->n); 589 if(rpcdebug) 590 fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n", 591 argv0, cp->host, cp->port, cp->xid, cp->n); 592 return 1; 593 } 594 595 static int 596 Iconv(Fmt *f) 597 { 598 char buf[16]; 599 ulong h; 600 601 h = va_arg(f->args, ulong); 602 snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld", 603 (h>>24)&0xff, (h>>16)&0xff, 604 (h>>8)&0xff, h&0xff); 605 return fmtstrcpy(f, buf); 606 } 607