📄 dhcpd.c
字号:
/* check for hard assignment */ if(rp->staticbinding){ if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){ warning(0, "!Request(%s via %I): %I not valid for %E", rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr); sendnak(rp, "not valid"); } sendack(rp, rp->ii.ipaddr, (StaticLease > minlease ? StaticLease : minlease), 1); return; } /* make sure the network makes sense */ if(!samenet(rp->ip, &rp->gii)){ warning(0, "!Request(%s via %I): bad forward of %I", rp->id, rp->gii.ipaddr, rp->ip); sendnak(rp, "wrong network"); return; } b = iptobinding(rp->ip, 0); if(b == nil){ warning(0, "!Request(%s via %I): no binding for %I for", rp->id, rp->gii.ipaddr, rp->ip); return; } if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){ warning(0, "!Request(%s via %I): %I not valid", rp->id, rp->gii.ipaddr, rp->ip); sendnak(rp, "not valid"); return; } b->offer = b->lease - now; sendack(rp, b->ip, b->offer, 1); } else if(validip(rp->ciaddr)){ /* * checking address - RENEWING or REBINDING * * these states are indistinguishable in our action. The only * difference is how close to lease expiration the client is. * If it is really close, it broadcasts the request hoping that * some server will answer. */ /* check for hard assignment */ if(rp->staticbinding){ if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){ warning(0, "!Request(%s via %I): %I not valid", rp->id, rp->gii.ipaddr, rp->ciaddr); sendnak(rp, "not valid"); } sendack(rp, rp->ii.ipaddr, (StaticLease > minlease ? StaticLease : minlease), 1); return; } /* make sure the network makes sense */ if(!samenet(rp->ciaddr, &rp->gii)){ warning(0, "!Request(%s via %I): bad forward of %I", rp->id, rp->gii.ipaddr, rp->ip); sendnak(rp, "wrong network"); return; } b = iptobinding(rp->ciaddr, 0); if(b == nil){ warning(0, "!Request(%s via %I): no binding for %I", rp->id, rp->gii.ipaddr, rp->ciaddr); return; } if(ipcmp(rp->ciaddr, b->ip) != 0){ warning(0, "!Request(%I via %s): %I not valid", rp->id, rp->gii.ipaddr, rp->ciaddr); sendnak(rp, "invalid ip address"); return; } mkoffer(b, rp->id, rp->leasetime); if(commitbinding(b) < 0){ warning(0, "!Request(%s via %I): can't commit %I", rp->id, rp->gii.ipaddr, b->ip); sendnak(rp, "can't commit binding"); return; } sendack(rp, b->ip, b->offer, 1); }}voidrcvdecline(Req *rp){ Binding *b; char buf[64]; if(rp->staticbinding) return; b = idtooffer(rp->id, &rp->gii); if(b == nil){ warning(0, "!Decline(%s via %I): no binding", rp->id, rp->gii.ipaddr); return; } /* mark ip address as in use */ snprint(buf, sizeof(buf), "declined by %s", rp->id); mkoffer(b, buf, 0x7fffffff); commitbinding(b);}voidrcvrelease(Req *rp){ Binding *b; if(rp->staticbinding) return; b = idtobinding(rp->id, &rp->gii, 0); if(b == nil){ warning(0, "!Release(%s via %I): no binding", rp->id, rp->gii.ipaddr); return; } if(strcmp(rp->id, b->boundto) != 0){ warning(0, "!Release(%s via %I): invalid release of %I", rp->id, rp->gii.ipaddr, rp->ip); return; } warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip); if(releasebinding(b, rp->id) < 0) warning(0, "release: couldn't release");}voidrcvinform(Req *rp){ Binding *b; if(rp->staticbinding){ sendack(rp, rp->ii.ipaddr, 0, 0); return; } b = iptobinding(rp->ciaddr, 0); if(b == nil){ warning(0, "!Inform(%s via %I): no binding for %I", rp->id, rp->gii.ipaddr, rp->ip); return; } sendack(rp, b->ip, 0, 0);}intsetsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr){ if(ipcmp(saddr, IPnoaddr) != 0){ v6tov4(siaddr, saddr); return 0; } else { v6tov4(siaddr, laddr); return 1; }}intismuted(Req *rp){ return mute || (mutestat && rp->staticbinding);}voidsendoffer(Req *rp, uchar *ip, int offer){ int n; ushort flags; Bootp *bp; OUdphdr *up; bp = rp->bp; up = rp->up; /* * set destination */ flags = nhgets(bp->flags); if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); hnputs(up->rport, 67); } else if(flags & Fbroadcast){ ipmove(up->raddr, IPv4bcast); hnputs(up->rport, 68); } else { ipmove(up->raddr, ip); if(bp->htype == 1) arpenter(up->raddr, bp->chaddr); hnputs(up->rport, 68); } /* * fill in standard bootp part */ bp->op = Bootreply; bp->hops = 0; hnputs(bp->secs, 0); memset(bp->ciaddr, 0, sizeof(bp->ciaddr)); v6tov4(bp->giaddr, rp->giaddr); v6tov4(bp->yiaddr, ip); setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr); strncpy(bp->sname, mysysname, sizeof(bp->sname)); strncpy(bp->file, rp->ii.bootf, sizeof(bp->file)); /* * set options */ byteopt(rp, ODtype, Offer); longopt(rp, ODlease, offer); addropt(rp, ODserverid, up->laddr); miscoptions(rp, ip); termopt(rp); logdhcpout(rp, "Offer"); /* * send */ n = rp->p - rp->buf; if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) warning(0, "offer: write failed: %r");}voidsendack(Req *rp, uchar *ip, int offer, int sendlease){ int n; ushort flags; Bootp *bp; OUdphdr *up; bp = rp->bp; up = rp->up; /* * set destination */ flags = nhgets(bp->flags); if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); hnputs(up->rport, 67); } else if(flags & Fbroadcast){ ipmove(up->raddr, IPv4bcast); hnputs(up->rport, 68); } else { ipmove(up->raddr, ip); if(bp->htype == 1) arpenter(up->raddr, bp->chaddr); hnputs(up->rport, 68); } /* * fill in standard bootp part */ bp->op = Bootreply; bp->hops = 0; hnputs(bp->secs, 0); v6tov4(bp->giaddr, rp->giaddr); v6tov4(bp->yiaddr, ip); setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr); strncpy(bp->sname, mysysname, sizeof(bp->sname)); strncpy(bp->file, rp->ii.bootf, sizeof(bp->file)); /* * set options */ byteopt(rp, ODtype, Ack); if(sendlease){ longopt(rp, ODlease, offer); } addropt(rp, ODserverid, up->laddr); miscoptions(rp, ip); termopt(rp); logdhcpout(rp, "Ack"); /* * send */ n = rp->p - rp->buf; if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) warning(0, "ack: write failed: %r");}voidsendnak(Req *rp, char *msg){ int n; Bootp *bp; OUdphdr *up; bp = rp->bp; up = rp->up; /* * set destination (always broadcast) */ if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); hnputs(up->rport, 67); } else { ipmove(up->raddr, IPv4bcast); hnputs(up->rport, 68); } /* * fill in standard bootp part */ bp->op = Bootreply; bp->hops = 0; hnputs(bp->secs, 0); v6tov4(bp->giaddr, rp->giaddr); memset(bp->ciaddr, 0, sizeof(bp->ciaddr)); memset(bp->yiaddr, 0, sizeof(bp->yiaddr)); memset(bp->siaddr, 0, sizeof(bp->siaddr)); /* * set options */ byteopt(rp, ODtype, Nak); addropt(rp, ODserverid, up->laddr); if(msg) stringopt(rp, ODmessage, msg); if(strncmp(rp->id, "id", 2) == 0) hexopt(rp, ODclientid, rp->id+2); termopt(rp); logdhcpout(rp, "Nak"); /* * send nak */ n = rp->p - rp->buf; if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) warning(0, "nak: write failed: %r");}voidbootp(Req *rp){ int n; Bootp *bp; OUdphdr *up; ushort flags; Iplifc *lifc; Info *iip; warning(0, "bootp %s %I->%I from %s via %I, file %s", rp->genrequest ? "generic" : (rp->p9request ? "p9" : ""), rp->up->raddr, rp->up->laddr, rp->id, rp->gii.ipaddr, rp->bp->file); if(nobootp) return; bp = rp->bp; up = rp->up; iip = &rp->ii; if(rp->staticbinding == 0){ warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr); return; } /* ignore if not for us */ if(*bp->sname){ if(strcmp(bp->sname, mysysname) != 0){ bp->sname[20] = 0; warning(0, "bootp for server %s", bp->sname); return; } } else slowdelay(rp); /* ignore if we don't know what file to load */ if(*bp->file == 0){ if(rp->genrequest && *iip->bootf2) /* if not plan 9 and we have an alternate file... */ strncpy(bp->file, iip->bootf2, sizeof(bp->file)); else if(*iip->bootf) strncpy(bp->file, iip->bootf, sizeof(bp->file)); else if(*bp->sname) /* if we were asked, respond no matter what */ bp->file[0] = '\0'; else { warning(0, "no bootfile for %I", iip->ipaddr); return; } } /* ignore if the file is unreadable */ if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){ warning(0, "inaccessible bootfile1 %s", bp->file); return; } bp->op = Bootreply; v6tov4(bp->yiaddr, iip->ipaddr); if(rp->p9request){ warning(0, "p9bootp: %I", iip->ipaddr); memmove(bp->optmagic, plan9opt, 4); if(iip->gwip == 0) v4tov6(iip->gwip, bp->giaddr); rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip, iip->auip, iip->gwip); sprint(optbuf, "%s", (char*)(bp->optmagic)); } else if(rp->genrequest){ warning(0, "genericbootp: %I", iip->ipaddr); memmove(bp->optmagic, genericopt, 4); miscoptions(rp, iip->ipaddr); termopt(rp); } else if(iip->vendor[0] != 0) { warning(0, "bootp vendor field: %s", iip->vendor); memset(rp->p, 0, 128-4); rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor); } else { memset(rp->p, 0, 128-4); rp->p += 128-4; } /* * set destination */ flags = nhgets(bp->flags); if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); hnputs(up->rport, 67); } else if(flags & Fbroadcast){ ipmove(up->raddr, IPv4bcast); hnputs(up->rport, 68); } else { v4tov6(up->raddr, bp->yiaddr); if(bp->htype == 1) arpenter(up->raddr, bp->chaddr); hnputs(up->rport, 68); } /* * select best local address if destination is directly connected */ lifc = findlifc(up->raddr); if(lifc) ipmove(up->laddr, lifc->ip); /* * our identity */ strncpy(bp->sname, mysysname, sizeof(bp->sname)); /* * set tftp server */ setsiaddr(bp->siaddr, iip->tftp, up->laddr); if(rp->genrequest && *iip->bootf2) setsiaddr(bp->siaddr, iip->tftp2, up->laddr); /* * RFC 1048 says that we must pad vendor field with * zeros until we have a 64 byte field. */ n = rp->p - rp->bp->optdata; if(n < 64-4) { memset(rp->p, 0, (64-4)-n); rp->p += (64-4)-n; } /* * send */ n = rp->p - rp->buf; if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) warning(0, "bootp: write failed: %r"); warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s", up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags), bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr, optbuf);}voidparseoptions(Req *rp){ int n, c, code; uchar *o, *p; p = rp->p; while(p < rp->e){ code = *p++; if(code == 255) break; if(code == 0) continue; /* ignore anything that's too long */ n = *p++; o = p; p += n; if(p > rp->e) return; switch(code){ case ODipaddr: /* requested ip address */ if(n == IPv4addrlen) v4tov6(rp->ip, o); break; case ODlease: /* requested lease time */ rp->leasetime = nhgetl(o); if(rp->leasetime > MaxLease || rp->leasetime < 0) rp->leasetime = MaxLease; break; case ODtype: c = *o; if(c < 10 && c > 0) rp->dhcptype = c; break; case ODserverid: if(n == IPv4addrlen) v4tov6(rp->server, o); break; case ODmessage: if(n > sizeof rp->msg-1) n = sizeof rp->msg-1; memmove(rp->msg, o, n); rp->msg[n] = 0; break; case ODmaxmsg: c = nhgets(o); c -= 28; c += OUdphdrsize; if(c > 0) rp->max = rp->buf + c; break; case ODclientid: if(n <= 1) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -