#include #include #include #include #include #include "arp.h" typedef struct Rarp Rarp; struct Rarp { uchar edst[6]; uchar esrc[6]; uchar type[2]; uchar hrd[2]; uchar pro[2]; uchar hln; uchar pln; uchar op[2]; uchar sha[6]; uchar spa[4]; uchar tha[6]; uchar tpa[4]; }; uchar myip[IPaddrlen]; uchar myether[6]; char rlog[] = "ipboot"; char *device = "ether0"; int debug; Ndb *db; char* lookup(char*, char*, char*, char*, int); void error(char *s) { syslog(1, rlog, "error %s: %r", s); exits(s); } char net[32]; void usage(void) { fprint(2, "usage: %s [-e device] [-x netmtpt] [-f ndb-file] [-d]\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { int edata, ectl; uchar buf[2048]; long n; Rarp *rp; char ebuf[16]; char ipbuf[64]; char file[128]; int arp; char *p, *ndbfile; ndbfile = nil; setnetmtpt(net, sizeof(net), nil); ARGBEGIN{ case 'e': p = ARGF(); if(p == nil) usage(); device = p; break; case 'd': debug = 1; break; case 'f': p = ARGF(); if(p == nil) usage(); ndbfile = p; break; case 'x': p = ARGF(); if(p == nil) usage(); setnetmtpt(net, sizeof(net), p); break; }ARGEND USED(argc, argv); fmtinstall('E', eipfmt); fmtinstall('I', eipfmt); fmtinstall('V', eipfmt); db = ndbopen(ndbfile); if(db == 0) error("can't open the database"); edata = dial(netmkaddr("0x8035", device, 0), 0, 0, &ectl); if(edata < 0) error("can't open ethernet"); if(myipaddr(myip, net) < 0) error("can't get my ip address"); sprint(ebuf, "%s/%s", net, device); if(myetheraddr(myether, ebuf) < 0) error("can't get my ether address"); snprint(file, sizeof(file), "%s/arp", net); if((arp = open(file, ORDWR)) < 0) fprint(2, "rarpd: can't open %s\n", file); switch(rfork(RFNOTEG|RFPROC|RFFDG)) { case -1: error("fork"); case 0: break; default: exits(0); } for(;;){ n = read(edata, buf, sizeof(buf)); if(n <= 0) error("reading"); if(n < sizeof(Rarp)){ syslog(debug, rlog, "bad packet size %ld", n); continue; } rp = (Rarp*)buf; if(rp->op[0]!=0 && rp->op[1]!=3){ syslog(debug, rlog, "bad op %d %d %E", rp->op[1], rp->op[0], rp->esrc); continue; } if(debug) syslog(debug, rlog, "rcv se %E si %V te %E ti %V", rp->sha, rp->spa, rp->tha, rp->tpa); sprint(ebuf, "%E", rp->tha); if(lookup("ether", ebuf, "ip", ipbuf, sizeof ipbuf) == nil){ syslog(debug, rlog, "client lookup failed: %s", ebuf); continue; } v4parseip(rp->tpa, ipbuf); memmove(rp->sha, myether, sizeof(rp->sha)); v6tov4(rp->spa, myip); rp->op[0] = 0; rp->op[1] = 4; memmove(rp->edst, rp->esrc, sizeof(rp->edst)); if(debug) syslog(debug, rlog, "send se %E si %V te %E ti %V", rp->sha, rp->spa, rp->tha, rp->tpa); if(write(edata, buf, 60) != 60) error("write failed"); if(arp < 0) continue; if(fprint(arp, "add %E %V", rp->esrc, rp->tpa) < 0) fprint(2, "can't write arp entry\n"); } } char* lookup(char *sattr, char *sval, char *tattr, char *tval, int len) { static Ndb *db; char *attrs[1]; Ndbtuple *t; if(db == nil) db = ndbopen(0); if(db == nil) return nil; if(sattr == nil) sattr = ipattr(sval); attrs[0] = tattr; t = ndbipinfo(db, sattr, sval, attrs, 1); if(t == nil) return nil; strncpy(tval, t->val, len); tval[len-1] = 0; ndbfree(t); return tval; }