#include #include #include "../port/bootp.h" #include "../port/arp.h" #include "../boot/boot.h" /* * il */ uchar fsip[4]; uchar auip[4]; uchar gwip[4]; uchar ipmask[4]; uchar ipaddr[4]; /* our ip address */ uchar eaddr[6]; /* our ether address */ uchar bcast[6]; /* our ether broadcast address */ uchar ipnet[4]; /* our ip network number */ static void arp(uchar*); static int arplisten(void); static ushort nhgets(uchar*); static void hnputs(uchar*, ushort); static void parseip(uchar*, char*); static int myetheraddr(uchar*, char*); static int parseether(uchar*, char*); static int mygetfields(char*, char**, int); static char* fmtaddr(uchar*); static void maskip(uchar*, uchar*, uchar*); static int equivip(uchar*, uchar*); static void ipconfig(Method*); static int ipdial(int*, char*, uchar*, int); static int catchint(void*, char*); uchar classmask[4][4] = { 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, }; int arpnotefd = -1; void configtcp(Method *mp) { ipconfig(mp); } int authtcp(void) { return -1; } int connecttcp(void) { int fd[2], rv; rv = ipdial(fd, "#Itcp/tcp", fsip, 17008); if(arpnotefd >= 0){ write(arpnotefd, "die", 3); close(arpnotefd); } if(cpuflag) sendmsg(fd[0], "push reboot"); if(rv >= 0) close(fd[0]); return fd[1]; } void configil(Method *mp) { ipconfig(mp); } int authil(void) { int fd[2]; if(ipdial(fd, "#Iil/il", auip, 17024) < 0) return -1; close(fd[0]); return fd[1]; } int connectil(void) { int fd[2], rv; rv = ipdial(fd, "#Iil/il", fsip, 17008); if(arpnotefd >= 0){ write(arpnotefd, "die", 3); close(arpnotefd); } if(cpuflag) sendmsg(fd[0], "push reboot"); if(rv >= 0) close(fd[0]); return fd[1]; } /* * configure ip. use bootp to get ip address, net mask, file server ip address, * authentication server ip address and gateway ip address. */ static void ipconfig(Method *mp) { int efd[2]; int fd; int ufd[2]; int n; int tries; Bootp req, *rp; char *field[4]; char buf[1600]; char buf2[64]; uchar ipbcast[4]; /* ip broadcast address for bootp */ /* determine bootp broadcast address from specified file system address */ if(*sys){ parseip(fsip, sys); parseip(gwip, sys); memmove(ipmask, classmask[fsip[0]>>6], sizeof(ipmask)); for(n = 0; n < sizeof(ipbcast); n++) ipbcast[n] = (ipmask[n] & fsip[n]) | ((~ipmask[n])&0xff); sprint(buf2, "%s!67", fmtaddr(ipbcast)); } else { memmove(ipmask, classmask[3], sizeof(ipmask)); strcpy(buf2, "255.255.255.255!67"); } memset(bcast, 0xff, sizeof(bcast)); /* ether broadcast address */ /* coinfigure/open ip */ myetheraddr(eaddr, "#l/ether"); /*print("my etheraddr is %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n", eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);/**/ if(plumb("#l/ether", "0x800", efd, 0) < 0) fatal("opening ip ether"); sendmsg(efd[0], "push arp"); sendmsg(efd[0], "push internet"); sendmsg(efd[0], "push tcp"); /* open a udp connection for bootp and fill in a packet */ if(plumb("#Iudp/udp", buf2, ufd, "68") < 0) fatal("opening bootp udp"); close(ufd[0]); memset(&req, 0, sizeof(req)); req.op = Bootrequest; req.htype = 1; /* ethernet */ req.hlen = 6; /* ethernet */ memmove(req.chaddr, eaddr, sizeof(req.chaddr)); memset(req.file, 0, sizeof(req.file)); strcpy(req.vend, "p9 "); /* broadcast bootp's till we get a reply, or 3 times around the loop */ atnotify(catchint, 1); tries = 0; field[0] = 0; for(rp = 0; rp == 0 && tries++ < 10;){ alarm(1000); if(write(ufd[1], &req, sizeof(req)) < 0) fatal("sending bootp"); for(;;){ rp = 0; memset(buf, 0, sizeof(buf)); n = read(ufd[1], buf, sizeof(buf)); if(n <= 0) break; rp = (Bootp*)buf; field[0] = 0;; if(memcmp(req.chaddr, rp->chaddr, 6) == 0 && rp->htype == 1 && rp->hlen == 6 && mygetfields(rp->vend+4, field, 4) == 4){ if(strncmp(rp->vend, "p9 ", 4) == 0){ memmove(ipaddr, rp->yiaddr, sizeof(ipaddr)); parseip(ipmask, field[0]); if(*sys == 0){ strcpy(sys, field[1]); parseip(fsip, field[1]); } parseip(auip, field[2]); parseip(gwip, field[3]); maskip(ipaddr, ipmask, ipnet); if(bootfile[0] == 0){ strncpy(bootfile, rp->file, sizeof(bootfile)); bootfile[sizeof(bootfile)-1] = 0; } break; } } } alarm(0); } close(ufd[1]); if(field[0]) /*print("I am %s sub %s fs %s au %s gw %s\n", fmtaddr(ipaddr), field[0], sys, field[2], field[3])/**/; else { errstr(buf); /* Clear timeout error from alarm */ mp->auth = 0; /* Dont know where to check password */ strcpy(buf2, "0.0.0.0"); outin("My IP address", buf2, sizeof(buf2)); parseip(ipaddr, buf2); strcpy(buf2, "255.255.255.0"); outin("My IP mask", buf2, sizeof(buf2)); parseip(ipmask, buf2); maskip(ipaddr, ipmask, ipnet); strcpy(buf2, "0.0.0.0"); outin("My IP gateway", buf2, sizeof(buf2)); parseip(gwip, buf2); if(*sys) strcpy(buf2, sys); else { strcpy(buf2, "0.0.0.0"); outin("filesystem IP address", buf2, sizeof(buf2)); } parseip(fsip, buf2); } /* set our ip address and mask */ n = sprint(buf2, "setip %s ", fmtaddr(ipaddr)); sprint(buf2+n, "%s", fmtaddr(ipmask)); sendmsg(efd[0], buf2); close(efd[0]); close(efd[1]); /* specify a routing gateway */ if(*gwip){ sprint(buf2, "add 0.0.0.0 0.0.0.0 %s", fmtaddr(gwip)); fd = open("#P/iproute", OWRITE); if(fd < 0) fatal("opening iproute"); if(sendmsg(fd, buf2) < 0) print("%s failed\n", buf2); close(fd); } /* a process to answer arps */ arpnotefd = arplisten(); } static int ipdial(int *ifd, char *dev, uchar *ip, int service) { uchar tmp[4]; char buf[64]; /* arp for first hop */ maskip(ip, ipmask, tmp); if(equivip(tmp, ipnet)) arp(ip); else arp(gwip); /* make the call */ sprint(buf, "%s!%d", fmtaddr(ip), service); if(plumb(dev, buf, ifd, 0) < 0){ fprint(2, "error dialing %s\n", buf); return -1; } return ifd[1]; } /* send an arprequest, wait for a reply */ static void arp(uchar *addr) { int afd[2]; int arpdev; int n; Arpentry entry; Arppkt req, *rp; char buf[1600]; if(plumb("#l/ether", "0x806", afd, 0) < 0) fatal("opening ip ether"); close(afd[0]); arpdev = open("#a/arp/data", OWRITE); if(arpdev < 0) fatal("opening arp/data"); /* arp for the file server or the gateway */ memset(&req, 0, sizeof(req)); memmove(req.tpa, addr, sizeof(req.tpa)); memset(req.d, 0xff, sizeof(req.d)); memmove(req.spa, ipaddr, sizeof(ipaddr)); memmove(req.sha, eaddr, sizeof(eaddr)); hnputs(req.type, ET_ARP); hnputs(req.hrd, 1); hnputs(req.pro, 0x800); req.hln = sizeof(req.sha); req.pln = sizeof(req.spa); hnputs(req.op, ARP_REQUEST); for(rp = 0; rp == 0;){ if(write(afd[1], &req, sizeof(req)) < 0) fatal("sending arpreq"); alarm(1000); for(;;){ rp = 0; memset(buf, 0, sizeof(buf)); n = read(afd[1], buf, sizeof(buf)); if(n <= 0) break; rp = (Arppkt*)buf; if(nhgets(rp->op) != ARP_REPLY) continue; memcpy(entry.etaddr, rp->sha, sizeof(entry.etaddr)); memcpy(entry.ipaddr, rp->spa, sizeof(entry.ipaddr)); if(write(arpdev, &entry, sizeof(entry)) < 0) warning("write arp entry"); print("arp: rcvd for %s\n", fmtaddr(rp->spa));/**/ if(equivip(rp->spa, addr)) break; } alarm(0); } close(arpdev); close(afd[1]); } /* * fork a process to answer arp requests for us. since * we will kill it after changing user id, we need to open the * note process here. arplisten returns the fd of the open note * process. */ static int arplisten(void) { int afd[2]; int n; int pid; Arppkt reply, *rp; char buf[1600]; switch(pid = fork()){ case -1: fatal("forking arplisten"); case 0: break; default: sprint(buf, "#p/%d/note", pid); return open(buf, OWRITE); } if(plumb("#l/ether", "0x806", afd, 0) < 0) fatal("opening ip ether"); atnotify(catchint, 0); for(;;){ memset(buf, 0, sizeof(buf)); n = read(afd[1], buf, sizeof(buf)); if(n <= 0) break; rp = (Arppkt*)buf; if(nhgets(rp->op) != ARP_REQUEST) continue; if(memcmp(rp->tpa, ipaddr, sizeof(ipaddr)) != 0) continue; memset(&reply, 0, sizeof(reply)); hnputs(reply.type, ET_ARP); hnputs(reply.hrd, 1); hnputs(reply.pro, 0x800); reply.hln = sizeof(reply.sha); reply.pln = sizeof(reply.spa); hnputs(reply.op, ARP_REPLY); memmove(reply.tha, rp->sha, sizeof(reply.tha)); memmove(reply.tpa, rp->spa, sizeof(reply.tpa)); memmove(reply.sha, eaddr, sizeof(eaddr)); memmove(reply.spa, ipaddr, sizeof(ipaddr)); memmove(reply.d, rp->s, sizeof(rp->s)); print("arplisten: reply to %s\n", fmtaddr(reply.tpa));/**/ if(write(afd[1], &reply, ARPSIZE) < 0) warning("write arp reply"); } exits(0); return 0; /* not reached */ } static ushort nhgets(uchar *val) { return (val[0]<<8) | val[1]; } static void hnputs(uchar *ptr, ushort val) { ptr[0] = val>>8; ptr[1] = val; } #define CLASS(p) ((*(uchar*)(p))>>6) static void parseip(uchar *to, char *from) { int i; char *p; p = from; memset(to, 0, 4); for(i = 0; i < 4 && *p; i++){ to[i] = strtoul(p, &p, 0); if(*p == '.') p++; } switch(CLASS(to)){ case 0: /* class A - 1 byte net */ case 1: if(i == 3){ to[3] = to[2]; to[2] = to[1]; to[1] = 0; } else if (i == 2){ to[3] = to[1]; to[1] = 0; } break; case 2: /* class B - 2 byte net */ if(i == 3){ to[3] = to[2]; to[2] = 0; } break; } } static int myetheraddr(uchar *to, char *dev) { char buf[256]; int n, fd; char *ptr; sprint(buf, "%s/1/stats", dev); fd = open(buf, OREAD); if(fd < 0) return -1; n = read(fd, buf, sizeof(buf)-1); close(fd); if(n <= 0) return -1; buf[n] = 0; ptr = strstr(buf, "addr: "); if(!ptr) return -1; ptr += 6; parseether(to, ptr); return 0; } static int parseether(uchar *to, char *from) { char nip[4]; char *p; int i; p = from; for(i = 0; i < 6; i++){ if(*p == 0) return -1; nip[0] = *p++; if(*p == 0) return -1; nip[1] = *p++; nip[2] = 0; to[i] = strtoul(nip, 0, 16); if(*p == ':') p++; } return 0; } static int mygetfields(char *lp, char **fields, int n) { int i; for(i=0; lp && *lp && i