dhcp6d: add minimal stateless DHCPv6 server for network boot and DNS configuration
This commit is contained in:
parent
eed90aa0ad
commit
a3f3e31b20
3 changed files with 576 additions and 2 deletions
|
@ -1,6 +1,6 @@
|
||||||
.TH DHCPD 8
|
.TH DHCPD 8
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dhcpd, dhcpleases, rarpd, tftpd \- Internet booting
|
dhcpd, dhcp6d, dhcpleases, rarpd, tftpd \- Internet booting
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.PP
|
.PP
|
||||||
.B ip/dhcpd
|
.B ip/dhcpd
|
||||||
|
@ -20,6 +20,13 @@ dhcpd, dhcpleases, rarpd, tftpd \- Internet booting
|
||||||
.PP
|
.PP
|
||||||
.B ip/dhcpleases
|
.B ip/dhcpleases
|
||||||
.PP
|
.PP
|
||||||
|
.B ip/dhcp6d
|
||||||
|
.RB [ -d ]
|
||||||
|
.RB [ -f
|
||||||
|
.IR ndb-file ]
|
||||||
|
.RB [ -x
|
||||||
|
.IR netmtpt ]
|
||||||
|
.PP
|
||||||
.B ip/rarpd
|
.B ip/rarpd
|
||||||
.RB [ -d ]
|
.RB [ -d ]
|
||||||
.RB [ -e
|
.RB [ -e
|
||||||
|
@ -37,7 +44,8 @@ dhcpd, dhcpleases, rarpd, tftpd \- Internet booting
|
||||||
These programs support booting over the Internet.
|
These programs support booting over the Internet.
|
||||||
They should all be run on the same server to
|
They should all be run on the same server to
|
||||||
allow other systems to be booted.
|
allow other systems to be booted.
|
||||||
.I Dhcpd
|
.IR Dhcpd ,
|
||||||
|
.I dhcp6d
|
||||||
and
|
and
|
||||||
.I tftpd
|
.I tftpd
|
||||||
are used to boot everything;
|
are used to boot everything;
|
||||||
|
@ -221,6 +229,10 @@ Use
|
||||||
as the minimum lease time for static addresses.
|
as the minimum lease time for static addresses.
|
||||||
.PD
|
.PD
|
||||||
.PP
|
.PP
|
||||||
|
.I Dhcp6d
|
||||||
|
provides DHCPv6 service for IPv6 clients. Only network boot and
|
||||||
|
DNS parameters are supported.
|
||||||
|
.PP
|
||||||
.I Dhcpleases
|
.I Dhcpleases
|
||||||
prints out the currently valid DHCP leases found in the
|
prints out the currently valid DHCP leases found in the
|
||||||
.B /lib/ndb/dhcp
|
.B /lib/ndb/dhcp
|
||||||
|
|
561
sys/src/cmd/ip/dhcp6d.c
Normal file
561
sys/src/cmd/ip/dhcp6d.c
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
/* minimal stateless DHCPv6 server for network boot */
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Eaddrlen = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Req Req;
|
||||||
|
struct Req
|
||||||
|
{
|
||||||
|
int tra;
|
||||||
|
|
||||||
|
Udphdr *udp;
|
||||||
|
Ipifc *ifc;
|
||||||
|
|
||||||
|
uchar mac[Eaddrlen];
|
||||||
|
uchar ips[IPaddrlen*8];
|
||||||
|
int nips;
|
||||||
|
|
||||||
|
Ndb *db;
|
||||||
|
Ndbtuple *t;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int t;
|
||||||
|
uchar *p;
|
||||||
|
uchar *e;
|
||||||
|
} req;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int t;
|
||||||
|
uchar *p;
|
||||||
|
uchar *e;
|
||||||
|
} resp;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Otab Otab;
|
||||||
|
struct Otab
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
int (*f)(uchar *, int, Otab*, Req*);
|
||||||
|
char *q[3];
|
||||||
|
int done;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Otab otab[];
|
||||||
|
static Ipifc *ipifcs;
|
||||||
|
static ulong starttime;
|
||||||
|
static int debug;
|
||||||
|
|
||||||
|
static uchar v6loopback[IPaddrlen] = {
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* open ndbfile as db if not already open. also check for stale data
|
||||||
|
* and reload as needed.
|
||||||
|
*/
|
||||||
|
static Ndb *
|
||||||
|
opendb(char *ndbfile)
|
||||||
|
{
|
||||||
|
static Ndb *db;
|
||||||
|
/* check no more often than once every minute */
|
||||||
|
if(db == nil)
|
||||||
|
db = ndbopen(ndbfile);
|
||||||
|
else if (ndbchanged(db))
|
||||||
|
ndbreopen(db);
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ipifc*
|
||||||
|
findifc(char *net, uchar ip[IPaddrlen])
|
||||||
|
{
|
||||||
|
Ipifc *ifc;
|
||||||
|
Iplifc *lifc;
|
||||||
|
|
||||||
|
ipifcs = readipifc(net, ipifcs, -1);
|
||||||
|
for(ifc = ipifcs; ifc != nil; ifc = ifc->next)
|
||||||
|
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
|
||||||
|
if(ipcmp(lifc->ip, ip) == 0)
|
||||||
|
return ifc;
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openlisten(char *net)
|
||||||
|
{
|
||||||
|
int fd, cfd;
|
||||||
|
char data[128], devdir[40];
|
||||||
|
Ipifc *ifc;
|
||||||
|
|
||||||
|
sprint(data, "%s/udp!*!dhcp6s", net);
|
||||||
|
cfd = announce(data, devdir);
|
||||||
|
if(cfd < 0)
|
||||||
|
sysfatal("can't announce: %r");
|
||||||
|
if(fprint(cfd, "headers") < 0)
|
||||||
|
sysfatal("can't set header mode: %r");
|
||||||
|
|
||||||
|
ipifcs = readipifc(net, ipifcs, -1);
|
||||||
|
for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
|
||||||
|
if(ifc->lifc == nil)
|
||||||
|
continue;
|
||||||
|
if(strcmp(ifc->dev, "/dev/null") == 0)
|
||||||
|
continue;
|
||||||
|
if(fprint(cfd, "addmulti %I ff02::1:2", ifc->lifc->ip) < 0)
|
||||||
|
fprint(2, "can't add interface %s: %r", ifc->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprint(data, "%s/data", devdir);
|
||||||
|
fd = open(data, ORDWR);
|
||||||
|
if(fd < 0)
|
||||||
|
sysfatal("open udp data: %r");
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
gettlv(int x, int *plen, uchar *p, uchar *e)
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
if(plen != nil)
|
||||||
|
*plen = 0;
|
||||||
|
while(p+4 <= e){
|
||||||
|
t = p[0]<<8 | p[1];
|
||||||
|
l = p[2]<<8 | p[3];
|
||||||
|
if(p+4+l > e)
|
||||||
|
break;
|
||||||
|
if(t == x){
|
||||||
|
if(plen != nil)
|
||||||
|
*plen = l;
|
||||||
|
return p+4;
|
||||||
|
}
|
||||||
|
p += l+4;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getv6ips(uchar *ip, int n, Ndbtuple *t, char *attr)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if(n < IPaddrlen)
|
||||||
|
return 0;
|
||||||
|
if(*attr == '@')
|
||||||
|
attr++;
|
||||||
|
for(; t != nil; t = t->entry){
|
||||||
|
if(strcmp(t->attr, attr) != 0)
|
||||||
|
continue;
|
||||||
|
if(parseip(ip, t->val) == -1)
|
||||||
|
continue;
|
||||||
|
if(isv4(ip))
|
||||||
|
continue;
|
||||||
|
ip += IPaddrlen;
|
||||||
|
r += IPaddrlen;
|
||||||
|
if(r >= n)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lookupips(uchar *ip, int n, Ndb *db, uchar mac[Eaddrlen])
|
||||||
|
{
|
||||||
|
Ndbtuple *t;
|
||||||
|
Ndbs s;
|
||||||
|
char val[256], *attr;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* use hardware address to find an ip address
|
||||||
|
*/
|
||||||
|
attr = "ether";
|
||||||
|
snprint(val, sizeof val, "%E", mac);
|
||||||
|
|
||||||
|
t = ndbsearch(db, &s, attr, val);
|
||||||
|
r = 0;
|
||||||
|
while(t != nil){
|
||||||
|
r += getv6ips(ip + r, n - r, t, "ip");
|
||||||
|
ndbfree(t);
|
||||||
|
if(r >= n)
|
||||||
|
break;
|
||||||
|
t = ndbsnext(&s, attr, val);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clearotab(void)
|
||||||
|
{
|
||||||
|
Otab *o;
|
||||||
|
|
||||||
|
for(o = otab; o->t != 0; o++)
|
||||||
|
o->done = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Otab*
|
||||||
|
findotab(int t)
|
||||||
|
{
|
||||||
|
Otab *o;
|
||||||
|
|
||||||
|
for(o = otab; o->t != 0; o++)
|
||||||
|
if(o->t == t)
|
||||||
|
return o;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addoption(Req *r, int t)
|
||||||
|
{
|
||||||
|
Otab *o;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(r->resp.p+4 > r->resp.e)
|
||||||
|
return -1;
|
||||||
|
o = findotab(t);
|
||||||
|
if(o == nil || o->f == nil || o->done)
|
||||||
|
return -1;
|
||||||
|
o->done = 1;
|
||||||
|
n = (*o->f)(r->resp.p+4, r->resp.e - (r->resp.p+4), o, r);
|
||||||
|
if(n < 0 || r->resp.p+4+n > r->resp.e)
|
||||||
|
return -1;
|
||||||
|
r->resp.p[0] = t>>8, r->resp.p[1] = t;
|
||||||
|
r->resp.p[2] = n>>8, r->resp.p[3] = n;
|
||||||
|
if(debug) fprint(2, "%d(%.*H)\n", t, n, r->resp.p+4);
|
||||||
|
r->resp.p += 4+n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "%s [-d] [-f ndbfile] [-x netmtpt]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *ndbfile = nil;
|
||||||
|
char *net = "/net";
|
||||||
|
uchar ibuf[4096], obuf[4096];
|
||||||
|
Req r[1];
|
||||||
|
int fd, n, i;
|
||||||
|
|
||||||
|
fmtinstall('H', encodefmt);
|
||||||
|
fmtinstall('I', eipfmt);
|
||||||
|
fmtinstall('E', eipfmt);
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'd':
|
||||||
|
debug++;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
ndbfile = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
net = EARGF(usage());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND;
|
||||||
|
|
||||||
|
starttime = time(nil) - 946681200UL;
|
||||||
|
|
||||||
|
if(opendb(ndbfile) == nil)
|
||||||
|
sysfatal("opendb: %r");
|
||||||
|
|
||||||
|
fd = openlisten(net);
|
||||||
|
|
||||||
|
/* put process in background */
|
||||||
|
if(!debug)
|
||||||
|
switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
|
||||||
|
default:
|
||||||
|
exits(nil);
|
||||||
|
case -1:
|
||||||
|
sysfatal("fork: %r");
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((n = read(fd, ibuf, sizeof(ibuf))) > Udphdrsize+4){
|
||||||
|
r->req.p = ibuf+Udphdrsize;
|
||||||
|
r->req.e = ibuf+n;
|
||||||
|
|
||||||
|
memmove(obuf, ibuf, Udphdrsize);
|
||||||
|
r->udp = (Udphdr*)obuf;
|
||||||
|
r->resp.p = obuf+Udphdrsize;
|
||||||
|
r->resp.e = &obuf[sizeof(obuf)];
|
||||||
|
|
||||||
|
r->tra = r->req.p[1]<<16 | r->req.p[2]<<8 | r->req.p[3];
|
||||||
|
r->req.t = r->req.p[0];
|
||||||
|
|
||||||
|
if((r->ifc = findifc(net, r->udp->ifcaddr)) == nil)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(debug)
|
||||||
|
fprint(2, "%I->%I(%s) typ=%d tra=%x\n",
|
||||||
|
r->udp->raddr, r->udp->laddr, r->ifc->dev,
|
||||||
|
r->req.t, r->tra);
|
||||||
|
|
||||||
|
switch(r->req.t){
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
case 1: /* solicit */
|
||||||
|
r->resp.t = 2; /* advertise */
|
||||||
|
break;
|
||||||
|
case 3: /* request */
|
||||||
|
case 11: /* information request */
|
||||||
|
r->resp.t = 7; /* reply */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r->resp.p[0] = r->resp.t;
|
||||||
|
r->resp.p[1] = r->tra>>16;
|
||||||
|
r->resp.p[2] = r->tra>>8;
|
||||||
|
r->resp.p[3] = r->tra;
|
||||||
|
|
||||||
|
r->req.p += 4;
|
||||||
|
r->resp.p += 4;
|
||||||
|
|
||||||
|
r->t = nil;
|
||||||
|
|
||||||
|
clearotab();
|
||||||
|
|
||||||
|
/* Server Identifier */
|
||||||
|
if(addoption(r, 2) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Client Identifier */
|
||||||
|
if(addoption(r, 1) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Lookup taret ip addresses */
|
||||||
|
if((r->db = opendb(ndbfile)) == nil)
|
||||||
|
continue;
|
||||||
|
r->nips = lookupips(r->ips, sizeof(r->ips), r->db, r->mac)/IPaddrlen;
|
||||||
|
if(debug){
|
||||||
|
for(i=0; i<r->nips; i++)
|
||||||
|
fprint(2, "ip=%I\n", r->ips+i*IPaddrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
addoption(r, 3);
|
||||||
|
addoption(r, 6);
|
||||||
|
|
||||||
|
write(fd, obuf, r->resp.p-obuf);
|
||||||
|
if(debug) fprint(2, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
oclientid(uchar *w, int n, Otab*, Req *r)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
uchar *p;
|
||||||
|
|
||||||
|
if((p = gettlv(1, &len, r->req.p, r->req.e)) == nil)
|
||||||
|
return -1;
|
||||||
|
if(len < 4+4+Eaddrlen || n < len)
|
||||||
|
return -1;
|
||||||
|
memmove(r->mac, p+len-Eaddrlen, Eaddrlen);
|
||||||
|
memmove(w, p, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
oserverid(uchar *w, int n, Otab*, Req *r)
|
||||||
|
{
|
||||||
|
if(n < 4+4+Eaddrlen)
|
||||||
|
return -1;
|
||||||
|
w[0] = 0, w[1] = 1; /* duid type: link layer address + time*/
|
||||||
|
w[2] = 0, w[3] = 1; /* hw type: ethernet */
|
||||||
|
w += 4;
|
||||||
|
w[0] = starttime>>24;
|
||||||
|
w[1] = starttime>>16;
|
||||||
|
w[2] = starttime>>8;
|
||||||
|
w[3] = starttime;
|
||||||
|
w += 4;
|
||||||
|
myetheraddr(w, r->ifc->dev);
|
||||||
|
return 4+4+Eaddrlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
oiana(uchar *w, int n, Otab*, Req *r)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
uchar *p;
|
||||||
|
|
||||||
|
p = gettlv(3, &len, r->req.p, r->req.e);
|
||||||
|
if(p == nil || len < 3*4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = 3*4 + (4+IPaddrlen+2*4)*r->nips;
|
||||||
|
if(n < len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memmove(w, p, 3*4);
|
||||||
|
w += 3*4;
|
||||||
|
|
||||||
|
for(i = 0; i < r->nips; i++){
|
||||||
|
w[0] = 0, w[1] = 5;
|
||||||
|
w[2] = 0, w[3] = IPaddrlen+2*4;
|
||||||
|
w += 4;
|
||||||
|
|
||||||
|
memmove(w, r->ips + i*IPaddrlen, IPaddrlen);
|
||||||
|
w += IPaddrlen;
|
||||||
|
|
||||||
|
memset(w, 255, 2*4);
|
||||||
|
w += 2*4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ndbtuple*
|
||||||
|
lookup(Req *r, char *av[], int ac)
|
||||||
|
{
|
||||||
|
Ndbtuple *t;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if(ac <= 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
t = nil;
|
||||||
|
if(r->nips > 0){
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* use the target ip's to lookup info if any */
|
||||||
|
for(i=0; i<r->nips; i++){
|
||||||
|
s = smprint("%I", &r->ips[i*IPaddrlen]);
|
||||||
|
t = ndbconcatenate(t, ndbipinfo(r->db, "ip", s, av, ac));
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Iplifc *lifc;
|
||||||
|
|
||||||
|
/* use the ipv6 networks on the interface */
|
||||||
|
for(lifc=r->ifc->lifc; lifc!=nil; lifc=lifc->next){
|
||||||
|
if(isv4(lifc->ip)
|
||||||
|
|| ipcmp(lifc->ip, v6loopback) == 0
|
||||||
|
|| ISIPV6LINKLOCAL(lifc->ip))
|
||||||
|
continue;
|
||||||
|
s = smprint("%I", lifc->net);
|
||||||
|
t = ndbconcatenate(t, ndbipinfo(r->db, "ip", s, av, ac));
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
oro(uchar*, int, Otab *o, Req *r)
|
||||||
|
{
|
||||||
|
uchar *p;
|
||||||
|
char *av[100];
|
||||||
|
int i, j, l, ac;
|
||||||
|
Ndbtuple *t;
|
||||||
|
|
||||||
|
p = gettlv(6, &l, r->req.p, r->req.e);
|
||||||
|
if(p == nil || l < 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ac = 0;
|
||||||
|
for(i=0; i<l; i+=2){
|
||||||
|
if((o = findotab(p[i]>>8 | p[i+1])) == nil || o->done)
|
||||||
|
continue;
|
||||||
|
for(j=0; j<3 && o->q[j]!=nil && ac<nelem(av); j++)
|
||||||
|
av[ac++] = o->q[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
r->t = lookup(r, av, ac);
|
||||||
|
|
||||||
|
if(debug){
|
||||||
|
fprint(2, "ndb(");
|
||||||
|
for(t = r->t; t != nil; t = t->entry){
|
||||||
|
fprint(2, "%s=%s ", t->attr, t->val);
|
||||||
|
if(t->entry != nil && t->entry != t->line)
|
||||||
|
fprint(2, "\n");
|
||||||
|
}
|
||||||
|
fprint(2, ")\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process the options */
|
||||||
|
for(i=0; i<l; i+=2)
|
||||||
|
addoption(r, p[i]>>8 | p[i+1]);
|
||||||
|
|
||||||
|
ndbfree(r->t);
|
||||||
|
r->t = nil;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
oservers(uchar *w, int n, Otab *o, Req *r)
|
||||||
|
{
|
||||||
|
return getv6ips(w, n, r->t, o->q[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
odomainlist(uchar *w, int n, Otab *o, Req *q)
|
||||||
|
{
|
||||||
|
Ndbtuple *t;
|
||||||
|
int l, r;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
for(t = q->t; t != nil; t = t->entry){
|
||||||
|
if(strcmp(t->attr, o->q[0]) != 0)
|
||||||
|
continue;
|
||||||
|
for(s = t->val; *s != 0; s++){
|
||||||
|
for(l = 0; *s != 0 && *s != '.'; l++)
|
||||||
|
s++;
|
||||||
|
if(r+1+l > n)
|
||||||
|
return -1;
|
||||||
|
w[r++] = l;
|
||||||
|
memmove(w+r, s-l, l);
|
||||||
|
r += l;
|
||||||
|
}
|
||||||
|
if(r >= n)
|
||||||
|
return -1;
|
||||||
|
w[r++] = 0;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
obootfileurl(uchar *w, int n, Otab *, Req *q)
|
||||||
|
{
|
||||||
|
uchar ip[IPaddrlen];
|
||||||
|
Ndbtuple *bootf;
|
||||||
|
|
||||||
|
if((bootf = ndbfindattr(q->t, q->t, "bootf")) == nil)
|
||||||
|
return -1;
|
||||||
|
if(strstr(bootf->val, "://") != nil)
|
||||||
|
return snprint((char*)w, n, "%s", bootf->val);
|
||||||
|
else if(getv6ips(ip, sizeof(ip), q->t, "tftp"))
|
||||||
|
return snprint((char*)w, n, "tftp://[%I]/%s", ip, bootf->val);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Otab otab[] = {
|
||||||
|
{ 1, oclientid, },
|
||||||
|
{ 2, oserverid, },
|
||||||
|
{ 3, oiana, },
|
||||||
|
{ 6, oro, },
|
||||||
|
{ 23, oservers, "@dns" },
|
||||||
|
{ 24, odomainlist, "dnsdomain" },
|
||||||
|
{ 59, obootfileurl, "bootf", "@tftp", },
|
||||||
|
{ 0 },
|
||||||
|
};
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
TARG = 6in4\
|
TARG = 6in4\
|
||||||
ayiya\
|
ayiya\
|
||||||
|
dhcp6d\
|
||||||
dhcpclient\
|
dhcpclient\
|
||||||
ftpd\
|
ftpd\
|
||||||
gping\
|
gping\
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue