diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-08-25 15:10:26 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-08-25 15:10:26 +0200 |
commit | 82c08a8a4469c4b4ba515d74addc7aac747a17d9 (patch) | |
tree | c91a7856e5404a7205600f3fc08b476c7027740b /sys/src/cmd/ip/dhcpd/dhcpd.c | |
parent | 4e938841f02de646d4e2e428453cbeede4051a57 (diff) |
ip/dhcpd: handle multiple networks on the same interface, dont get confused by v6 interface address
Diffstat (limited to 'sys/src/cmd/ip/dhcpd/dhcpd.c')
-rw-r--r-- | sys/src/cmd/ip/dhcpd/dhcpd.c | 148 |
1 files changed, 75 insertions, 73 deletions
diff --git a/sys/src/cmd/ip/dhcpd/dhcpd.c b/sys/src/cmd/ip/dhcpd/dhcpd.c index d10067900..5ec03b70e 100644 --- a/sys/src/cmd/ip/dhcpd/dhcpd.c +++ b/sys/src/cmd/ip/dhcpd/dhcpd.c @@ -19,6 +19,7 @@ struct Req int fd; /* for reply */ Bootp *bp; Udphdr *up; + Ipifc *ifc; uchar *e; /* end of received message */ uchar *p; /* options pointer */ uchar *max; /* max end of reply */ @@ -164,7 +165,7 @@ char *optname[256] = void addropt(Req*, int, uchar*); void addrsopt(Req*, int, uchar**, int); -void arpenter(uchar*, uchar*); +void arpenter(uchar*, uchar*, uchar*); void bootp(Req*); void byteopt(Req*, int, uchar); void dhcp(Req*); @@ -188,7 +189,7 @@ int readlast(int, uchar*, int); char* readsysname(void); void remrequested(Req*, int); void sendack(Req*, uchar*, int, int); -void sendnak(Req*, char*); +void sendnak(Req*, uchar*, char*); void sendoffer(Req*, uchar*, int); void stringopt(Req*, int, char*); void termopt(Req*); @@ -324,7 +325,6 @@ main(int argc, char **argv) void proto(Req *rp, int n) { - uchar relip[IPaddrlen]; char buf[64]; now = time(0); @@ -332,8 +332,6 @@ proto(Req *rp, int n) rp->e = rp->buf + n; rp->bp = (Bootp*)rp->buf; rp->up = (Udphdr*)rp->buf; - if (ipcmp(rp->up->laddr, IPv4bcast) == 0) - ipmove(rp->up->laddr, rp->up->ifcaddr); rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE; rp->p = rp->bp->optdata; v4tov6(rp->giaddr, rp->bp->giaddr); @@ -342,22 +340,15 @@ proto(Req *rp, int n) if(pptponly && rp->bp->htype != 0) return; - ipifcs = readipifc(net, ipifcs, -1); - if(validip(rp->giaddr)) - ipmove(relip, rp->giaddr); - else if(validip(rp->up->raddr)) - ipmove(relip, rp->up->raddr); - else - ipmove(relip, rp->up->laddr); - if(rp->e < (uchar*)rp->bp->sname){ - warning(0, "packet too short"); - return; - } if(rp->bp->op != Bootrequest){ warning(0, "not bootrequest"); return; } + if(rp->e < (uchar*)rp->bp->sname){ + warning(0, "packet too short"); + return; + } if(rp->e >= rp->bp->optdata){ if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0) rp->p9request = 1; @@ -385,12 +376,26 @@ proto(Req *rp, int n) rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen); } - /* info about gateway */ - if(lookupip(relip, &rp->gii, 1) < 0){ - warning(0, "lookupip failed"); + ipifcs = readipifc(net, ipifcs, -1); + rp->ifc = findifc(rp->up->ifcaddr); + if(rp->ifc == nil){ + warning(0, "no interface"); return; } + if(validip(rp->giaddr)){ + /* info about gateway */ + if(lookupip(rp->giaddr, &rp->gii, 1) < 0){ + warning(0, "lookupip failed"); + return; + } + rp->gii.ifc = nil; + } else { + /* no gateway, directly connected */ + memset(&rp->gii, 0, sizeof(rp->gii)); + rp->gii.ifc = rp->ifc; + } + /* info about target system */ if(lookup(rp->bp, &rp->ii, &rp->gii) == 0) if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0) @@ -498,13 +503,13 @@ rcvrequest(Req *rp) /* check for hard assignment */ if(rp->staticbinding){ - if(forme(rp->server)) + if(findifc(rp->server) != rp->ifc) { + warning(0, "!Request(%s via %I): for server %I not me", + rp->id, rp->gii.ipaddr, rp->server); + } else sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1); - else - warning(0, "!Request(%s via %I): for server %I not me", - rp->id, rp->gii.ipaddr, rp->server); return; } @@ -514,13 +519,13 @@ rcvrequest(Req *rp) if(b == nil){ warning(0, "!Request(%s via %I): no offer", rp->id, rp->gii.ipaddr); - if(forme(rp->server)) - sendnak(rp, "no offer for you"); + if(findifc(rp->server) == rp->ifc) + sendnak(rp, rp->server, "no offer for you"); return; } /* if not for me, retract offer */ - if(!forme(rp->server)){ + if(findifc(rp->server) != rp->ifc){ b->expoffer = 0; warning(0, "!Request(%s via %I): for server %I not me", rp->id, rp->gii.ipaddr, rp->server); @@ -534,13 +539,13 @@ rcvrequest(Req *rp) if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){ warning(0, "!Request(%s via %I): requests %I, not %I", rp->id, rp->gii.ipaddr, rp->ip, b->ip); - sendnak(rp, "bad ip address option"); + sendnak(rp, rp->ip, "bad ip address option"); return; } 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"); + sendnak(rp, b->ip, "can't commit binding"); return; } sendack(rp, b->ip, b->offer, 1); @@ -556,10 +561,10 @@ rcvrequest(Req *rp) if(ipcmp(rp->ip, rp->ii.ipaddr) != 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); + sendnak(rp, rp->ip, "not valid"); + } else + sendack(rp, rp->ip, (staticlease > minlease? + staticlease: minlease), 1); return; } @@ -567,7 +572,6 @@ rcvrequest(Req *rp) 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); @@ -579,7 +583,7 @@ rcvrequest(Req *rp) if(ipcmp(rp->ip, b->ip) != 0 || now > b->lease){ warning(0, "!Request(%s via %I): %I not valid", rp->id, rp->gii.ipaddr, rp->ip); - sendnak(rp, "not valid"); + sendnak(rp, rp->ip, "not valid"); return; } b->offer = b->lease - now; @@ -599,10 +603,10 @@ rcvrequest(Req *rp) 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); + sendnak(rp, rp->ciaddr, "not valid"); + } else + sendack(rp, rp->ciaddr, (staticlease > minlease? + staticlease: minlease), 1); return; } @@ -610,26 +614,25 @@ rcvrequest(Req *rp) 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); + rp->id, rp->ciaddr, rp->ciaddr); return; } if(ipcmp(rp->ciaddr, b->ip) != 0){ - warning(0, "!Request(%I via %s): %I not valid", + warning(0, "!Request(%s via %I): %I not valid", rp->id, rp->gii.ipaddr, rp->ciaddr); - sendnak(rp, "invalid ip address"); + sendnak(rp, rp->ciaddr, "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"); + sendnak(rp, b->ip, "can't commit binding"); return; } sendack(rp, b->ip, b->offer, 1); @@ -730,9 +733,8 @@ sendoffer(Req *rp, uchar *ip, int offer) bp = rp->bp; up = rp->up; - /* - * set destination - */ + localip(up->laddr, ip, rp->ifc); + flags = nhgets(bp->flags); if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); @@ -743,7 +745,7 @@ sendoffer(Req *rp, uchar *ip, int offer) } else { ipmove(up->raddr, ip); if(bp->htype == 1) - arpenter(up->raddr, bp->chaddr); + arpenter(up->raddr, bp->chaddr, up->ifcaddr); hnputs(up->rport, 68); } @@ -790,9 +792,8 @@ sendack(Req *rp, uchar *ip, int offer, int sendlease) bp = rp->bp; up = rp->up; - /* - * set destination - */ + localip(up->laddr, ip, rp->ifc); + flags = nhgets(bp->flags); if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); @@ -803,7 +804,7 @@ sendack(Req *rp, uchar *ip, int offer, int sendlease) } else { ipmove(up->raddr, ip); if(bp->htype == 1) - arpenter(up->raddr, bp->chaddr); + arpenter(up->raddr, bp->chaddr, up->ifcaddr); hnputs(up->rport, 68); } @@ -841,7 +842,7 @@ sendack(Req *rp, uchar *ip, int offer, int sendlease) } void -sendnak(Req *rp, char *msg) +sendnak(Req *rp, uchar *ip, char *msg) { int n; Bootp *bp; @@ -850,6 +851,8 @@ sendnak(Req *rp, char *msg) bp = rp->bp; up = rp->up; + localip(up->laddr, ip, rp->ifc); + /* * set destination (always broadcast) */ @@ -900,7 +903,6 @@ bootp(Req *rp) Bootp *bp; Udphdr *up; ushort flags; - Iplifc *lifc; Info *iip; warning(0, "bootp %s %I->%I from %s via %I, file %s", @@ -960,10 +962,8 @@ bootp(Req *rp) 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); + 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); @@ -979,9 +979,8 @@ bootp(Req *rp) rp->p += 128-4; } - /* - * set destination - */ + localip(up->laddr, iip->ipaddr, iip->ifc); + flags = nhgets(bp->flags); if(validip(rp->giaddr)){ ipmove(up->raddr, rp->giaddr); @@ -992,18 +991,11 @@ bootp(Req *rp) } else { v4tov6(up->raddr, bp->yiaddr); if(bp->htype == 1) - arpenter(up->raddr, bp->chaddr); + arpenter(up->raddr, bp->chaddr, up->ifcaddr); 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)); @@ -1136,13 +1128,23 @@ miscoptions(Req *rp, uchar *ip) char *p; char *attr[100], **a; Ndbtuple *t; + Iplifc *lifc; for(i=0; i<nelem(addrs); i++) addrs[i] = &x[i*IPaddrlen]; /* always supply these */ - maskopt(rp, OBmask, rp->gii.ipmask); - if(validip(rp->gii.gwip)){ + if(validip(rp->ii.ipmask)) + maskopt(rp, OBmask, rp->ii.ipmask); + else if(validip(rp->gii.ipmask)) + maskopt(rp, OBmask, rp->gii.ipmask); + else if((lifc = findlifc(ip, rp->ifc)) != nil) + maskopt(rp, OBmask, lifc->mask); + + if(validip(rp->ii.gwip)){ + remrequested(rp, OBrouter); + addropt(rp, OBrouter, rp->ii.gwip); + } else if(validip(rp->gii.gwip)){ remrequested(rp, OBrouter); addropt(rp, OBrouter, rp->gii.gwip); } else if(validip(rp->giaddr)){ @@ -1581,7 +1583,7 @@ hexopt(Req *rp, int t, char *str) } void -arpenter(uchar *ip, uchar *ether) +arpenter(uchar *ip, uchar *ether, uchar *ifcaddr) { int f; char buf[256]; @@ -1592,7 +1594,7 @@ arpenter(uchar *ip, uchar *ether) syslog(debug, blog, "open %s: %r", buf); return; } - fprint(f, "add ether %I %E", ip, ether); + fprint(f, "add ether %I %E %I", ip, ether, ifcaddr); close(f); } @@ -1650,7 +1652,7 @@ logdhcp(Req *rp) void logdhcpout(Req *rp, char *type) { - syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s", + syslog(0, blog, "%s(%I->%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s", type, rp->up->laddr, rp->up->raddr, rp->id, rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf); } |