Commit 0d8ef0e9 authored by Leigh Stoller's avatar Leigh Stoller

Bash proxyDHCP into using the DB to get the pxe boot path and IP

address. Added a pxe_boot_path field to the nodes table, and set
it to boss.emulab.net:/tftpboot/pxeboot for pxe booting pcs. Note
that the IP address is mandatory; proxyDHCP will fail if it gets
just a path out of the DB.
parent e0e84a30
......@@ -19,8 +19,10 @@ include $(TESTBED_SRCDIR)/GNUmakerules
DBFLAG = -DUSE_MYSQL_DB
#DBFLAG = -DUSE_CFILE_DB
#DBFLAG = -DUSE_NULL_DB
DBSRC = bootinfo_null.c bootinfo_cfile.c bootinfo_mysql.c
DBOBJ = bootinfo_null.o bootinfo_cfile.o bootinfo_mysql.o
BI_DBSRC = bootinfo_null.c bootinfo_cfile.c bootinfo_mysql.c
BI_DBOBJ = bootinfo_null.o bootinfo_cfile.o bootinfo_mysql.o
PR_DBSRC = proxydhcp_cfile.c proxydhcp_mysql.c
PR_DBOBJ = proxydhcp_cfile.o proxydhcp_mysql.o
INCS = -I/usr/local/include
......@@ -33,20 +35,30 @@ INCS = -I/usr/local/include
CFLAGS += $(INCS) $(DBFLAG) -DSOLARIS -DHAVE_SOCKADDR_SA_LEN -DUSE_RECVMSG \
-DCONFPATH='"$(INSTALL_ETCDIR)/"' -DTBDBNAME='"$(TBDBNAME)"'
proxydhcp: proxydhcp.o
cc $(CFLAGS) -o proxydhcp proxydhcp.o $(LFLAGS)
proxydhcp: proxydhcp.o $(PR_DBOBJ)
cc $(CFLAGS) $(DBFLAG) $(INCS) \
-o proxydhcp proxydhcp.o $(PR_DBOBJ) \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient
bootinfo: bootinfo.o $(DBOBJ)
bootinfo: bootinfo.o $(BI_DBOBJ)
cc $(CFLAGS) $(DBFLAG) $(INCS) \
-o bootinfo bootinfo.o $(DBOBJ) \
-o bootinfo bootinfo.o $(BI_DBOBJ) \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient
testbootinfo_mysql: bootinfo_mysql.c
cc $(CFLAGS) -DUSE_MYSQL_DB -DTEST $(INCS) \
-o testmysql $< \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient
testmysql: bootinfo_mysql.c
testbootinfo_cfile: bootinfo_cfile.c
cc $(CFLAGS) -DUSE_CFILE_DB -DTEST $(INCS) -o testcfile $< $(LFLAGS)
testproxydhcp_mysql: proxydhcp_mysql.c
cc $(CFLAGS) -DUSE_MYSQL_DB -DTEST $(INCS) \
-o testmysql $< \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient
testcfile: bootinfo_cfile.c
testproxydhcp_cfile: proxydhcp_cfile.c
cc $(CFLAGS) -DUSE_CFILE_DB -DTEST $(INCS) -o testcfile $< $(LFLAGS)
install: all
......
......@@ -62,33 +62,14 @@ typedef struct {
BOOTPH dhcppak;
/*
* Trivial config file format.
* DB interface
*/
struct config {
struct in_addr cip;
struct in_addr sip;
char bootprog[256];
};
#define MAX_CONFIGS 256
struct config *configurations[MAX_CONFIGS];
struct config *find_config(struct in_addr *addr);
int parse_configs(char *filename);
int open_db(void);
int query_db(struct in_addr, struct in_addr *, char *, int);
int close_db(void);
int binlmode = 0;
int parsehost(char *hostname) {
struct hostent *he;
if (!isdigit(hostname[0])) {
he = gethostbyname(hostname);
if (he == NULL) {
fprintf(stderr,"Unknown host %s\n",hostname);
exit(1);
}
return *(int *)he->h_addr;
} else
return inet_addr(hostname);
}
int gettag(uchar *p, uchar tag, uchar *data, uchar *pend) {
uchar t;
t=*p;
......@@ -155,18 +136,15 @@ void main(int argc, char *argv[])
{
int servsock;
struct sockaddr_in server, client;
struct in_addr sip;
int clientlength;
int i, sip, gip, argn=1;
char *p, filename[128], ifname[IFNAMSIZ+1];
int i, argn=1;
char *p, bootprog[256], ifname[IFNAMSIZ+1];
char arguments[256];
if(argc < 2) {
fprintf(stderr, "usage : "
"proxydhcp [-ifname] config_filename\n");
exit(1);
}
memset(ifname,0,sizeof(ifname));
if (argv[1][0]=='-')
if (argc == 2 && argv[1][0]=='-')
{
/* Bind to a specific interface */
#ifdef SOLARIS
......@@ -178,9 +156,8 @@ void main(int argc, char *argv[])
argn=2;
}
gip = 0;
if (parse_configs(argv[argn])) {
fprintf(stderr, "Error on config file\n");
if (open_db()) {
fprintf(stderr, "Error opening database\n");
exit(1);
}
......@@ -294,15 +271,16 @@ void main(int argc, char *argv[])
continue;
}
if ((configp = find_config(&client.sin_addr)) == NULL) {
if (query_db(client.sin_addr,
&sip, bootprog, sizeof(bootprog))) {
fprintf(stderr, "No matching record!\n");
continue;
}
dhcppak.op=BOOTP_REPLY;
*((int *)dhcppak.sip)=configp->sip.s_addr;
*((int *)dhcppak.sip)=sip.s_addr;
*((int *)dhcppak.gip)=0;
strcpy(dhcppak.bootfile,configp->bootprog);
strcpy(dhcppak.bootfile, bootprog);
/* Add DHCP message type optopn (53) */
data[0]=(binlmode ? DHCPACK : DHCPOFFER);
......@@ -365,69 +343,3 @@ void main(int argc, char *argv[])
}
}
}
int
parse_configs(char *filename)
{
FILE *fp;
int i, count = 0;
char buf[BUFSIZ], *bp, client[256], server[256], bootprog[256];
struct config *configp;
if ((fp = fopen(filename, "r")) == NULL)
return 1;
while (1) {
if ((bp = fgets(buf, BUFSIZ, fp)) == NULL)
break;
if (*bp == '\n' || *bp == '#')
continue;
if (count >= MAX_CONFIGS) {
fclose(fp);
return 1;
}
sscanf(bp, "%s %s %s\n", &client, &server, &bootprog);
configp = (struct config *) calloc(sizeof(*configp), 1);
if (!configp) {
fclose(fp);
return 1;
}
configurations[count++] = configp;
configp->cip.s_addr = parsehost(client);
configp->sip.s_addr = parsehost(server);
strcpy(configp->bootprog, bootprog);
}
for (i = 0; i < count; i++) {
char c[256], s[256];
configp = configurations[i];
strcpy(c, inet_ntoa(configp->cip));
strcpy(s, inet_ntoa(configp->sip));
printf("%s %s %s\n", c, s, configp->bootprog);
}
fclose(fp);
return 0;
}
struct config *
find_config(struct in_addr *addr)
{
int i;
struct config *configp;
for (i = 0; i < MAX_CONFIGS; i++) {
if ((configp = configurations[i]) == NULL)
return 0;
if (addr->s_addr == configp->cip.s_addr)
return configp;
}
return 0;
}
......@@ -4,4 +4,4 @@ IDIR=@prefix@/sbin
EDIR=@prefix@/etc
killall proxydhcp
${IDIR}/proxydhcp ${EDIR}/proxydhcp.conf > /dev/null 2>&1 &
${IDIR}/proxydhcp > /dev/null 2>&1 &
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <syslog.h>
/*
* Trivial config file format.
*/
#ifdef USE_CFILE_DB
#define CFILE "proxydhcp.conf"
struct config {
struct in_addr client;
struct in_addr server;
char bootprog[1];
/* bootprog is variable length */
};
#define MAX_CONFIGS 256
static int numconfigs;
static struct config *configurations[MAX_CONFIGS];
static struct config *find_config(struct in_addr addr);
static int parse_configs(char *filename);
int
open_db(void)
{
char cfile[BUFSIZ];
#ifdef TEST
strcpy(cfile, CFILE);
#else
strcpy(cfile, CONFPATH);
strcat(cfile, CFILE);
#endif
return parse_configs(cfile);
}
int
query_db(struct in_addr ipaddr, struct in_addr *sip,
char *bootprog, int bootlen)
{
struct config *configp;
if ((configp = find_config(ipaddr)) == 0)
return 1;
if (strlen(configp->bootprog) >= bootlen)
return 1;
sip->s_addr = configp->server.s_addr;
strcpy(bootprog, configp->bootprog);
return 0;
}
int
close_db(void)
{
int i;
for (i = 0; i < numconfigs; i++)
if (configurations[i])
free(configurations[i]);
numconfigs = 0;
return 0;
}
static int
parse_host(char *name)
{
struct hostent *he;
if (!isdigit(name[0])) {
he = gethostbyname(name);
if (he == 0) {
syslog(LOG_ERR, "%s: unknown host", name);
return 0;
}
return *(int *)he->h_addr;
}
return inet_addr(name);
}
static int
parse_configs(char *filename)
{
FILE *fp;
int i;
char buf[BUFSIZ], *bp, *cix;
char client[256], server[256], bootprog[256];
struct config *configp;
int ipaddr;
if ((fp = fopen(filename, "r")) == NULL) {
syslog(LOG_ERR, "%s: cannot open", filename);
return 1;
}
while (1) {
if ((bp = fgets(buf, BUFSIZ, fp)) == NULL)
break;
if (*bp == '\n' || *bp == '#')
continue;
if (numconfigs >= MAX_CONFIGS) {
syslog(LOG_ERR, "%s: too many lines", filename);
fclose(fp);
return 1;
}
sscanf(bp, "%s %s %s\n", &client, &server, &bootprog);
configp = (struct config *)
calloc(sizeof(*configp) + strlen(bootprog), 1);
if (!configp) {
bad:
syslog(LOG_ERR, "%s: parse error", filename);
fclose(fp);
close_db();
return 1;
}
configurations[numconfigs++] = configp;
strcpy(configp->bootprog, bootprog);
if ((ipaddr = parse_host(client)) == 0)
goto bad;
configp->client.s_addr = ipaddr;
if ((ipaddr = parse_host(server)) == 0)
goto bad;
configp->server.s_addr = ipaddr;
}
fclose(fp);
return 0;
}
static struct config *
find_config(struct in_addr addr)
{
int i;
struct config *configp;
for (i = 0; i < numconfigs; i++)
if ((configp = configurations[i]) != NULL &&
addr.s_addr == configp->client.s_addr)
return configp;
return 0;
}
#ifdef TEST
#include <stdarg.h>
void
syslog(int prio, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
fprintf(stderr, "\n");
}
main(int argc, char **argv)
{
struct in_addr ipaddr, server;
char *bootprog;
if (open_db() != 0) {
printf("bad config file\n");
exit(1);
}
while (--argc > 0) {
if (ipaddr.s_addr = parse_host(*++argv)) {
if (query_db(ipaddr, &server, &bootprog) == 0) {
printf("%s: %s %s\n", *argv,
inet_ntoa(server), bootprog);
} else
printf("failed\n");
} else
printf("bogus IP address `%s'\n", *argv);
}
close_db();
exit(0);
}
#endif
#endif
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <syslog.h>
#ifdef USE_MYSQL_DB
#include <mysql/mysql.h>
static char dbname[] = TBDBNAME;
static MYSQL db;
static int parse_pathspec(char *path, struct in_addr *sip, char **filename);
#include <stdarg.h>
void
syslog(int prio, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
fprintf(stderr, "\n");
}
int
open_db(void)
{
return 0;
}
int
query_db(struct in_addr ipaddr, struct in_addr *sip,
char *bootprog, int bootlen)
{
char querybuf[1024];
int n, nrows, ncols, part;
MYSQL db;
MYSQL_RES *res;
MYSQL_ROW row;
char dbquery[] =
"select pxe_boot_path from nodes as n "
"left join interfaces as i on "
"i.node_id=n.node_id "
"where i.IP = '%s'";
#define PXEBOOT_PATH 0
n = snprintf(querybuf, sizeof querybuf, dbquery, inet_ntoa(ipaddr));
if (n > sizeof querybuf) {
syslog(LOG_ERR, "query too long for buffer");
return 1;
}
mysql_init(&db);
if (mysql_real_connect(&db, 0, 0, 0, dbname, 0, 0, 0) == 0) {
syslog(LOG_ERR, "%s: connect failed: %s",
dbname, mysql_error(&db));
return 1;
}
/* Debug message into log:
syslog(LOG_ERR, "USING QUERY: %s", querybuf);
*/
if (mysql_real_query(&db, querybuf, n) != 0) {
syslog(LOG_ERR, "%s: query failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
res = mysql_store_result(&db);
if (res == 0) {
syslog(LOG_ERR, "%s: store_result failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
mysql_close(&db);
nrows = (int)mysql_num_rows(res);
switch (nrows) {
case 0:
syslog(LOG_ERR, "%s: no entry for host %s",
dbname, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
case 1:
break;
default:
syslog(LOG_ERR, "%s: %d entries for IP %s, using first",
dbname, nrows, inet_ntoa(ipaddr));
break;
}
ncols = (int)mysql_num_fields(res);
switch (ncols) {
case 1: /* Should have 1 fields */
break;
default:
syslog(LOG_ERR, "%s: %d fields in query for IP %s!",
dbname, ncols, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
}
row = mysql_fetch_row(res);
/*
* Check next_boot_path. If set, assume it is a multiboot kernel.
*/
if (row[PXEBOOT_PATH] != 0 && row[PXEBOOT_PATH][0] != '\0') {
char *filename;
if (parse_pathspec(row[PXEBOOT_PATH], sip, &filename))
goto bad;
if (strlen(filename) >= bootlen)
goto bad;
strcpy(bootprog, filename);
mysql_free_result(res);
return 0;
}
bad:
mysql_free_result(res);
return 1;
}
#undef PXEBOOT_PATH
int
close_db(void)
{
return 0;
}
/*
* Split a pathspec into the IP and Path.
*/
static int
parse_pathspec(char *path, struct in_addr *sip, char **filename)
{
char *p = path;
struct hostent *he;
strsep(&p, ":");
if (!p || (he = gethostbyname(path)) == 0)
return 1;
memcpy((char *)sip, he->h_addr, sizeof(sip));
*filename = p;
return 0;
}
#ifdef TEST
static int
parse_host(char *name)
{
struct hostent *he;
if (!isdigit(name[0])) {
he = gethostbyname(name);
if (he == 0) {
syslog(LOG_ERR, "%s: unknown host", name);
return 0;
}
return *(int *)he->h_addr;
}
return inet_addr(name);
}
main(int argc, char **argv)
{
struct in_addr ipaddr, server;
char bootprog[256];
if (open_db() != 0) {
printf("bad config file\n");
exit(1);
}
while (--argc > 0) {
if (ipaddr.s_addr = parse_host(*++argv)) {
if (query_db(ipaddr,
&server, bootprog, sizeof(bootprog))
== 0) {
printf("%s: %s %s\n", *argv,
inet_ntoa(server), bootprog);
} else
printf("failed\n");
} else
printf("bogus IP address `%s'\n", *argv);
}
close_db();
exit(0);
}
#endif
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment