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:
cinap_lenrek 2022-02-05 01:34:22 +00:00
parent dc72530159
commit e4f30c89f4
2 changed files with 106 additions and 6 deletions

View file

@ -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

View file

@ -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);
}