ip/tftpd: add -m argument for name substitution using regular expressions
This allows mapping incoming filenames to a different name using regular expressions, followed by subtitutions of the %[ICE] format strings. I needed this to have individual cmdline.txt files for netbooted raspberry pi's. In this example, i map cmdline.txt to %C, which gets substituted for /cfg/pxe/$ether of the client.
This commit is contained in:
parent
dc72530159
commit
e4f30c89f4
2 changed files with 106 additions and 6 deletions
|
@ -43,7 +43,9 @@ dhcpd, dhcp6d, dhcpleases, rarpd, tftpd \- Internet booting
|
||||||
.RB [ -x
|
.RB [ -x
|
||||||
.IR netmtpt ]
|
.IR netmtpt ]
|
||||||
.RB [ -n
|
.RB [ -n
|
||||||
.IR namespace-file ]
|
.IR nsfile ]
|
||||||
|
.RB [ -m
|
||||||
|
.IR mapfile ]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
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
|
||||||
|
@ -323,6 +325,26 @@ Restricts access to only those files rooted in the
|
||||||
.TP
|
.TP
|
||||||
.B n
|
.B n
|
||||||
Sets the namespace file (default /lib/namespace).
|
Sets the namespace file (default /lib/namespace).
|
||||||
|
.TP
|
||||||
|
.B m
|
||||||
|
Loads name substitutions from
|
||||||
|
.IR mapfile .
|
||||||
|
The format is a space or tab separated two-column text
|
||||||
|
with the first column being a regular expression
|
||||||
|
(see
|
||||||
|
.IR regexp (6))
|
||||||
|
that is matched against the requested file name
|
||||||
|
and the second column contains a subsitution.
|
||||||
|
Lines starting with
|
||||||
|
.B #
|
||||||
|
are ignored.
|
||||||
|
Occurances in the resulting filename of
|
||||||
|
.BR %I ,
|
||||||
|
.B %C
|
||||||
|
or
|
||||||
|
.B %E
|
||||||
|
are replaced with the ip, cfgpxe name or ether MAC of
|
||||||
|
of the client.
|
||||||
.PD
|
.PD
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.BR /lib/ndb/dhcp " directory of dynamic address files
|
.BR /lib/ndb/dhcp " directory of dynamic address files
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <auth.h>
|
#include <auth.h>
|
||||||
#include <bio.h>
|
#include <bio.h>
|
||||||
#include <ip.h>
|
#include <ip.h>
|
||||||
|
#include <regexp.h>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -63,6 +64,13 @@ struct Opt {
|
||||||
int max;
|
int max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct Map Map;
|
||||||
|
struct Map {
|
||||||
|
Reprog *re;
|
||||||
|
char *sub;
|
||||||
|
Map *next;
|
||||||
|
};
|
||||||
|
|
||||||
int dbg;
|
int dbg;
|
||||||
int restricted;
|
int restricted;
|
||||||
int pid;
|
int pid;
|
||||||
|
@ -85,6 +93,7 @@ void ack(int, ushort);
|
||||||
void clrcon(void);
|
void clrcon(void);
|
||||||
void setuser(void);
|
void setuser(void);
|
||||||
void remoteaddr(char*, char*, int);
|
void remoteaddr(char*, char*, int);
|
||||||
|
void readmapfile(char*);
|
||||||
void doserve(int);
|
void doserve(int);
|
||||||
|
|
||||||
char bigbuf[32768];
|
char bigbuf[32768];
|
||||||
|
@ -94,6 +103,7 @@ char *dirsl;
|
||||||
int dirsllen;
|
int dirsllen;
|
||||||
char *homedir = "/";
|
char *homedir = "/";
|
||||||
char *nsfile = nil;
|
char *nsfile = nil;
|
||||||
|
Map *namemap = nil;
|
||||||
char flog[] = "ipboot";
|
char flog[] = "ipboot";
|
||||||
char net[Maxpath];
|
char net[Maxpath];
|
||||||
|
|
||||||
|
@ -109,7 +119,7 @@ static char *opnames[] = {
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
fprint(2, "usage: %s [-dr] [-h homedir] [-s svc] [-x netmtpt]\n",
|
fprint(2, "usage: %s [-dr] [-h homedir] [-s svc] [-x netmtpt] [-n nsfile] [-m mapfile]\n",
|
||||||
argv0);
|
argv0);
|
||||||
exits("usage");
|
exits("usage");
|
||||||
}
|
}
|
||||||
|
@ -142,6 +152,9 @@ main(int argc, char **argv)
|
||||||
case 'n':
|
case 'n':
|
||||||
nsfile = EARGF(usage());
|
nsfile = EARGF(usage());
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
readmapfile(EARGF(usage()));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}ARGEND
|
}ARGEND
|
||||||
|
@ -177,7 +190,6 @@ main(int argc, char **argv)
|
||||||
if (cfd < 0)
|
if (cfd < 0)
|
||||||
sysfatal("announcing on %s: %r", buf);
|
sysfatal("announcing on %s: %r", buf);
|
||||||
syslog(dbg, flog, "tftpd started on %s dir %s", buf, adir);
|
syslog(dbg, flog, "tftpd started on %s dir %s", buf, adir);
|
||||||
// setuser();
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
lcfd = listen(adir, ldir);
|
lcfd = listen(adir, ldir);
|
||||||
if(lcfd < 0)
|
if(lcfd < 0)
|
||||||
|
@ -368,16 +380,27 @@ optlog(char *bytes, char *p, int dlen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* substitute name from namemap file and
|
||||||
* replace one occurrence of %[ICE] with ip, cfgpxe name, or ether mac, resp.
|
* replace one occurrence of %[ICE] with ip, cfgpxe name, or ether mac, resp.
|
||||||
* we can't easily use $ because u-boot has stranger quoting rules than sh.
|
* we can't easily use $ because u-boot has stranger quoting rules than sh.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
mapname(char *file)
|
mapname(char *file)
|
||||||
{
|
{
|
||||||
int nf;
|
char sub[1024], *p, *newnm, *cur, *arpf, *ln, *remip, *bang;
|
||||||
char *p, *newnm, *cur, *arpf, *ln, *remip, *bang;
|
|
||||||
char *fields[4];
|
|
||||||
Biobuf *arp;
|
Biobuf *arp;
|
||||||
|
Map *map;
|
||||||
|
|
||||||
|
for(map = namemap; map != nil; map = map->next){
|
||||||
|
Resub subs[16];
|
||||||
|
|
||||||
|
memset(subs, 0, sizeof(subs));
|
||||||
|
if(regexec(map->re, file, subs, nelem(subs))){
|
||||||
|
regsub(map->sub, sub, sizeof(sub), subs, nelem(subs));
|
||||||
|
file = sub;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p = strchr(file, '%');
|
p = strchr(file, '%');
|
||||||
if (p == nil || p[1] == '\0')
|
if (p == nil || p[1] == '\0')
|
||||||
|
@ -411,6 +434,9 @@ mapname(char *file)
|
||||||
break;
|
break;
|
||||||
/* read lines looking for remip in 3rd field of 4 */
|
/* read lines looking for remip in 3rd field of 4 */
|
||||||
while ((ln = Brdline(arp, '\n')) != nil) {
|
while ((ln = Brdline(arp, '\n')) != nil) {
|
||||||
|
char *fields[4];
|
||||||
|
int nf;
|
||||||
|
|
||||||
ln[Blinelen(arp)-1] = 0;
|
ln[Blinelen(arp)-1] = 0;
|
||||||
nf = tokenize(ln, fields, nelem(fields));
|
nf = tokenize(ln, fields, nelem(fields));
|
||||||
if (nf >= 4 && strcmp(fields[2], remip) == 0) {
|
if (nf >= 4 && strcmp(fields[2], remip) == 0) {
|
||||||
|
@ -448,8 +474,12 @@ doserve(int fd)
|
||||||
while(*p && dlen--)
|
while(*p && dlen--)
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
syslog(dbg, flog, "tftpd %d mode %s file %s", pid, mode, file);
|
||||||
|
|
||||||
file = mapname(file); /* we don't free the result; minor leak */
|
file = mapname(file); /* we don't free the result; minor leak */
|
||||||
|
|
||||||
|
syslog(dbg, flog, "tftpd %d file -> %s", pid, file);
|
||||||
|
|
||||||
if(dlen == 0) {
|
if(dlen == 0) {
|
||||||
nak(fd, 0, "bad tftpmode");
|
nak(fd, 0, "bad tftpmode");
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -772,3 +802,51 @@ remoteaddr(char *dir, char *raddr, int len)
|
||||||
n--;
|
n--;
|
||||||
raddr[n] = 0;
|
raddr[n] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
readmapfile(char *file)
|
||||||
|
{
|
||||||
|
Map **link, *map;
|
||||||
|
Biobuf *bio;
|
||||||
|
char *s, *p, *d;
|
||||||
|
int line;
|
||||||
|
|
||||||
|
/* go to last entry */
|
||||||
|
for(link = &namemap; *link; link = &(*link)->next)
|
||||||
|
;
|
||||||
|
|
||||||
|
if((bio = Bopen(file, OREAD)) == nil)
|
||||||
|
sysfatal("open: %r");
|
||||||
|
|
||||||
|
for(line = 1; (s = Brdstr(bio, '\n', 1)) != nil; free(s), line++){
|
||||||
|
p = s;
|
||||||
|
while(strchr("\t ", *p))
|
||||||
|
p++;
|
||||||
|
|
||||||
|
if(*p == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(d = strchr(p, '\t'))
|
||||||
|
*d++ = '\0';
|
||||||
|
else if(d = strchr(p, ' '))
|
||||||
|
*d++ = '\0';
|
||||||
|
else {
|
||||||
|
fprint(2, "%s:%d: ignored: %s\n", file, line, p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while(strchr("\t ", *d))
|
||||||
|
d++;
|
||||||
|
map = malloc(sizeof(Map));
|
||||||
|
map->re = regcomp(p);
|
||||||
|
if(map->re == nil){
|
||||||
|
fprint(2, "%s:%d: syntax error: %s\n", file, line, p);
|
||||||
|
free(map);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
map->sub = strdup(d);
|
||||||
|
map->next = nil;
|
||||||
|
*link = map;
|
||||||
|
link = &map->next;
|
||||||
|
}
|
||||||
|
Bterm(bio);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue