Date: Fri, 13 Oct 2000 09:17:42 +0200 From: Danny Braniss <danny@cs.huji.ac.il> To: freebsd-hackers@freebsd.org Subject: bootp/diskless/kenv Message-ID: <E13jz66-0001aJ-00@sexta.cs.huji.ac.il>
next in thread | raw e-mail | index | archive | help
Im including a modified lib/libstand/bootp.c for evaluation. It has:
o- fixes for evaluation of netmask - only if not supplied.
o- puts in the environment the dhcp stuff
it does not - yet -:
do any good check for string overflow.
check for environment buffer overflow - haven't found out
how to do it yet
since kenv can now be used early on the diskless boot process, i think
it should be placed in /bin and staticaly linked.
danny
--------- cut here --------
/* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner Exp $ */
/*
* Copyright (c) 1992 Regents of the University of California.
* All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL)
* $FreeBSD: src/lib/libstand/bootp.c,v 1.1.1.1.6.1 2000/09/10 02:52:19 ps Exp
$
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <string.h>
/* #define BOOTP_DEBUGxx */
#define SUPPORT_DHCP
/*#define BOOTP_DEBUG /* danny */
#if defined(BOOTP_DEBUG) || defined(BOOTP_DEBUGxx)
int debug=1;
#endif
#include "stand.h"
#include "net.h"
#include "netif.h"
#include "bootp.h"
struct in_addr servip;
static n_long smask;
static time_t bot;
static char vm_rfc1048[4] = VM_RFC1048;
#ifdef BOOTP_VEND_CMU
static char vm_cmu[4] = VM_CMU;
#endif
/* Local forwards */
static ssize_t bootpsend(struct iodesc *, void *, size_t);
static ssize_t bootprecv(struct iodesc *, void *, size_t, time_t);
static int vend_rfc1048(u_char *, u_int);
#ifdef BOOTP_VEND_CMU
static void vend_cmu(u_char *);
#endif
#ifdef SUPPORT_DHCP
static char expected_dhcpmsgtype = -1, dhcp_ok;
struct in_addr dhcp_serverip;
#endif
static void setenv_dhcp(u_char *cp, u_int len);
/* Fetch required bootp infomation */
void
bootp(sock, flag)
int sock;
int flag;
{
struct iodesc *d;
register struct bootp *bp;
struct {
u_char header[HEADER_SIZE];
struct bootp wbootp;
} wbuf;
struct {
u_char header[HEADER_SIZE];
struct bootp rbootp;
} rbuf;
int j;
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootp: socket=%d\n", sock);
#endif
if (!bot)
bot = getsecs();
if (!(d = socktodesc(sock))) {
printf("bootp: bad socket. %d\n", sock);
return;
}
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootp: d=%lx\n", (long)d);
#endif
bp = &wbuf.wbootp;
bzero(bp, sizeof(*bp));
bp->bp_op = BOOTREQUEST;
bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */
bp->bp_hlen = 6;
bp->bp_xid = htonl(d->xid);
MACPY(d->myea, bp->bp_chaddr);
strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file));
bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048));
j = sizeof(vm_rfc1048);
#ifdef SUPPORT_DHCP
bp->bp_vend[j++] = TAG_DHCP_MSGTYPE;
bp->bp_vend[j++] = 1;
bp->bp_vend[j++] = DHCPDISCOVER;
#if 0
/*
* We send an RFC 1533 "Maximum DHCP Message Size" option, saying we
* can do 1200 bytes. If we don't ISC DHCPD will limit the answer to
* 64 bytes and root/swap and similar will be dropped.
*/
bp->bp_vend[j++] = TAG_MAXSIZE;
bp->bp_vend[j++] = 2;
bp->bp_vend[j++] = 1200 / 256;
bp->bp_vend[j++] = 1200 % 256;
#endif
/*
* If we are booting from PXE, we want to send the string
* 'PXEClient' to the DHCP server so you have the option of
* only responding to PXE aware dhcp requests.
*/
if (flag & BOOTP_PXE) {
char *classid;
int len;
bp->bp_vend[j++] = TAG_CLASSID;
#if 0
bp->bp_vend[j++] = 9;
bcopy("PXEClient", &bp->bp_vend[j], 9);
j += 9;
#else
classid = "FreeBSDc";
bp->bp_vend[j++] = len = strlen(classid);
bcopy(classid, &bp->bp_vend[j], len);
j += len;
#endif
}
expected_dhcpmsgtype = DHCPOFFER;
dhcp_ok = 0;
#endif
bp->bp_vend[j++] = TAG_END;
d->myip.s_addr = INADDR_ANY;
d->myport = htons(IPPORT_BOOTPC);
d->destip.s_addr = INADDR_BROADCAST;
d->destport = htons(IPPORT_BOOTPS);
if(sendrecv(d,
bootpsend, bp, sizeof(*bp),
bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
== -1) {
printf("bootp: no reply\n");
return;
}
#ifdef SUPPORT_DHCP
if(dhcp_ok) {
u_int32_t leasetime;
int j;
j = 6;
bp->bp_vend[j++] = DHCPREQUEST;
bp->bp_vend[j++] = TAG_REQ_ADDR;
bp->bp_vend[j++] = 4;
bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[j], 4);
j += 4;
bp->bp_vend[j++] = TAG_SERVERID;
bp->bp_vend[j++] = 4;
bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[j], 4);
j += 4;
bp->bp_vend[j++] = TAG_LEASETIME;
bp->bp_vend[j++] = 4;
leasetime = htonl(300);
bcopy(&leasetime, &bp->bp_vend[j], 4);
j += 4;
if (flag & BOOTP_PXE) {
#if 0
bp->bp_vend[j++] = TAG_CLASSID;
bp->bp_vend[j++] = 9;
bcopy("PXEClient", &bp->bp_vend[j], 9);
j += 9;
#else
char *classid;
int len;
classid = "FreeBSDc";
bp->bp_vend[j++] = len = strlen(classid);
bcopy(classid, &bp->bp_vend[j], len);
j += len;
#endif
}
bp->bp_vend[j++] = TAG_END;
expected_dhcpmsgtype = DHCPACK;
if(sendrecv(d,
bootpsend, bp, sizeof(*bp),
bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
== -1) {
printf("DHCPREQUEST failed\n");
return;
}
}
#endif /* SUPPORT_DHCP */
myip = d->myip = rbuf.rbootp.bp_yiaddr;
servip = rbuf.rbootp.bp_siaddr;
if(rootip.s_addr == INADDR_ANY) rootip = servip;
bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile));
bootfile[sizeof(bootfile) - 1] = '\0';
if(smask == 0) {
if(IN_CLASSA(ntohl(myip.s_addr)))
smask = htonl(IN_CLASSA_NET);
else
if(IN_CLASSB(ntohl(myip.s_addr)))
smask = htonl(IN_CLASSB_NET);
else
smask = htonl(IN_CLASSC_NET);
}
/* Get subnet (or natural net) mask */
netmask = smask;
/* We need a gateway if root is on a different net */
if (!SAMENET(myip, rootip, netmask)) {
#ifdef BOOTP_DEBUG
if (debug)
printf("need gateway for root ip\n");
#endif
}
/* Toss gateway if on a different net */
if (!SAMENET(myip, gateip, netmask)) {
printf("gateway ip (%s) is bad!\n", inet_ntoa(gateip));
gateip.s_addr = 0;
}
/* Bump xid so next request will be unique. */
++d->xid;
}
/* Transmit a bootp request */
static ssize_t
bootpsend(d, pkt, len)
register struct iodesc *d;
register void *pkt;
register size_t len;
{
register struct bootp *bp;
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootpsend: d=%lx called.\n", (long)d);
#endif
bp = pkt;
bp->bp_secs = htons((u_short)(getsecs() - bot));
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootpsend: calling sendudp\n");
#endif
return (sendudp(d, pkt, len));
}
static ssize_t
bootprecv(d, pkt, len, tleft)
register struct iodesc *d;
register void *pkt;
register size_t len;
time_t tleft;
{
register ssize_t n;
register struct bootp *bp;
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootp_recvoffer: called\n");
#endif
n = readudp(d, pkt, len, tleft);
if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
goto bad;
bp = (struct bootp *)pkt;
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
(long)bp, (int)n);
#endif
if (bp->bp_xid != htonl(d->xid)) {
#ifdef BOOTP_DEBUG
if (debug) {
printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
d->xid, ntohl(bp->bp_xid));
}
#endif
goto bad;
}
#ifdef BOOTP_DEBUGxx
if (debug)
printf("bootprecv: got one!\n");
#endif
/* Suck out vendor info */
if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0)
goto bad;
}
#ifdef BOOTP_VEND_CMU
else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
vend_cmu(bp->bp_vend);
#endif
else
printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend);
return(n);
bad:
errno = 0;
return (-1);
}
static int
vend_rfc1048(cp, len)
register u_char *cp;
u_int len;
{
register u_char *ep;
register int size;
register u_char tag;
setenv_dhcp(cp, len);
#ifdef BOOTP_DEBUG
if (debug)
printf("vend_rfc1048 bootp info. len=%d\n", len);
#endif
ep = cp + len;
/* Step over magic cookie */
cp += sizeof(int);
while (cp < ep) {
tag = *cp++;
size = *cp++;
switch(tag) {
case 0:
continue;
case TAG_END:
break;
case TAG_SUBNET_MASK:
bcopy(cp, &smask, sizeof(smask));
break;
case TAG_GATEWAY:
bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr));
break;
case TAG_SWAPSERVER:
/* let it override bp_siaddr */
bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr));
break;
case TAG_ROOTPATH:
strncpy(rootpath, (char *)cp, sizeof(rootpath));
rootpath[size] = '\0';
break;
case TAG_HOSTNAME:
strncpy(hostname, (char *)cp, sizeof(hostname));
hostname[size] = '\0';
break;
#ifdef SUPPORT_DHCP
case TAG_DHCP_MSGTYPE:
if(*cp != expected_dhcpmsgtype)
return(-1);
dhcp_ok = 1;
break;
case TAG_SERVERID:
bcopy(cp, &dhcp_serverip.s_addr, sizeof(dhcp_serverip.s_addr));
break;
#endif
#ifdef BOOTP_DEBUG
default:
if (debug)
printf("unknown tag:%d size=%d\n", tag, size);
#endif
}
cp += size;
}
return(0);
}
#ifdef BOOTP_VEND_CMU
static void
vend_cmu(cp)
u_char *cp;
{
register struct cmu_vend *vp;
#ifdef BOOTP_DEBUGxx
if (debug)
printf("vend_cmu bootp info.\n");
#endif
vp = (struct cmu_vend *)cp;
if (vp->v_smask.s_addr != 0) {
smask = vp->v_smask.s_addr;
}
if (vp->v_dgate.s_addr != 0) {
gateip = vp->v_dgate;
}
}
#endif
/*
| DHCP Option names, formats and codes, from RFC1533.
*/
#define __IP 1
#define __TXT 2
#define __8 3
#define __16 4
#define __32 5
#define __VE 6
struct dhcp_opt {
int tag;
int fmt;
char *desc;
} dhcp_opt[] = {
#define _DHCP(num, fmt, dsc) {num, fmt, dsc}
_DHCP(1, __IP, "subnet-mask"),
_DHCP(2, __32, "time-offset"),
_DHCP(3, __IP, "routers"),
_DHCP(4, __IP, "time-servers"),
_DHCP(5, __IP, "ien116-name-servers"),
_DHCP(6, __IP, "domain-name-servers"),
_DHCP(7, __IP, "log-servers"),
_DHCP(8, __IP, "cookie-servers"),
_DHCP(9, __IP, "lpr-servers"),
_DHCP(10, __IP, "impress-servers"),
_DHCP(11, __IP, "resource-location-servers"),
_DHCP(12, __TXT, "host-name"),
_DHCP(13, __16, "boot-size"),
_DHCP(14, __TXT, "merit-dump"),
_DHCP(15, __TXT, "domain-name"),
_DHCP(16, __IP, "swap-server"),
_DHCP(17, __TXT, "root-path"),
_DHCP(18, __TXT, "extensions-path"),
_DHCP(19, __8, "ip-forwarding"),
_DHCP(20, __8, "non-local-source-routing"),
_DHCP(21, __IP, "policy-filter"),
_DHCP(22, __16, "max-dgram-reassembly"),
_DHCP(23, __8, "default-ip-ttl"),
_DHCP(24, __32, "path-mtu-aging-timeout"),
_DHCP(25, __16, "path-mtu-plateau-table"),
_DHCP(26, __16, "interface-mtu"),
_DHCP(27, __8, "all-subnets-local"),
_DHCP(28, __IP, "broadcast-address"),
_DHCP(29, __8, "perform-mask-discovery"),
_DHCP(30, __8, "mask-supplier"),
_DHCP(31, __8, "router-discovery"),
_DHCP(32, __IP, "router-solicitation-address"),
_DHCP(33, __IP, "static-routes"),
_DHCP(34, __8, "trailer-encapsulation"),
_DHCP(35, __32, "arp-cache-timeout"),
_DHCP(36, __8, "ieee802-3-encapsulation"),
_DHCP(37, __8, "default-tcp-ttl"),
_DHCP(38, __32, "tcp-keepalive-interval"),
_DHCP(39, __8, "tcp-keepalive-garbage"),
_DHCP(40, __TXT, "nis-domain"),
_DHCP(41, __IP, "nis-servers"),
_DHCP(42, __IP, "ntp-servers"),
_DHCP(43, __VE, "vendor-encapsulated-options"),
_DHCP(44, __IP, "netbios-name-servers"),
_DHCP(45, __IP, "netbios-dd-server"),
_DHCP(46, __8, "netbios-node-type"),
_DHCP(47, __TXT, "netbios-scope"),
_DHCP(48, __IP, "font-servers"),
_DHCP(49, __IP, "x-display-manager"),
_DHCP(50, __IP, "dhcp-requested-address"),
_DHCP(51, __32, "dhcp-lease-time"),
_DHCP(52, __8, "dhcp-option-overload"),
_DHCP(53, __8, "dhcp-message-type"),
_DHCP(54, __IP, "dhcp-server-identifier"),
_DHCP(55, __8, "dhcp-parameter-request-list"),
_DHCP(56, __TXT, "dhcp-message"),
_DHCP(57, __16, "dhcp-max-message-size"),
_DHCP(58, __32, "dhcp-renewal-time"),
_DHCP(59, __32, "dhcp-rebinding-time"),
_DHCP(60, __TXT, "vendor-class-identifier"),
_DHCP(61, __TXT, "dhcp-client-identifier"),
_DHCP(64, __TXT, "nisplus-domain"),
_DHCP(65, __IP, "nisplus-servers"),
_DHCP(66, __TXT, "tftp-server-name"),
_DHCP(67, __TXT, "bootfile-name"),
_DHCP(68, __IP, "mobile-ip-home-agent"),
_DHCP(69, __IP, "smtp-server"),
_DHCP(70, __IP, "pop-server"),
_DHCP(71, __IP, "nntp-server"),
_DHCP(72, __IP, "www-server"),
_DHCP(73, __IP, "finger-server"),
_DHCP(74, __IP, "irc-server"),
_DHCP(75, __IP, "streettalk-server"),
_DHCP(76, __IP, "streettalk-directory-assistance-server"),
_DHCP(77, __TXT, "user-class"),
_DHCP(85, __IP, "nds-servers"),
_DHCP(86, __TXT, "nds-tree-name"),
_DHCP(87, __TXT, "nds-context"),
_DHCP(210, __TXT, "authenticate"),
{0}
};
struct dhcp_opt optdef = _DHCP(0, __TXT, "option-%d");
#undef _DHCP
static void
setenv_dhcp(u_char *cp, u_int len)
{
u_char *ep;
int size;
u_char tag;
char env[128], val[512], *vp, tags[512], *tp;
struct in_addr in_ip;
ep = cp + len;
cp += sizeof(vm_rfc1048); /* hopefully this was checked? */
tp = tags;
while(cp < ep) {
struct dhcp_opt *op;
tag = *cp++;
size = *cp++;
if(tag == TAG_END)
break;
if(tag == 0)
continue;
for(op = dhcp_opt; op->tag; op++)
if(op->tag >= tag)
break;
if(op->tag != tag)
op = &optdef;
vp = val;
switch(op->fmt) {
case __VE: /* vendor specific */
while(size-- > 0) {
sprintf(vp, "%02x", *cp++);
vp += 2;
}
break;
case __IP: /* ip address */
while(size > 0) {
if(vp != val)
*vp++ = ',';
bcopy(cp, &in_ip.s_addr, sizeof(in_ip.s_addr));
sprintf(vp, "%s", inet_ntoa(in_ip));
vp += strlen(vp);
size -= 4;
cp += 4;
}
break;
case __TXT:
bcopy(cp, val, size);
val[size] = 0;
cp += size;
break;
case __8:
case __16:
case __32:
while(size > 0) {
int n = 0;
if(vp != val)
*vp++ = ',';
switch(op->fmt) {
case __8:
sprintf(vp, "%02x", cp[0]);
n = 1;
break;
case __16:
sprintf(vp, "%02x%02x", cp[0], cp[1]);
n = 2;
break;
case __32:
sprintf(vp, "%02x%02x%02x%02x", cp[0], cp[1], cp[2], cp[3]);
n = 4;
break;
}
cp += n;
size -= n;
vp += strlen(vp);
}
break;
}
sprintf(tp, "%03d:", tag);
tp += strlen(tp);
if(op == &optdef)
sprintf(env, "dhcp.option-%d", tag);
else
sprintf(env, "dhcp.%s", op->desc);
#ifdef BOOTP_DEBUG
if(debug)
printf("%s %s\n", env, val);
#endif
setenv(env, val, 1);
}
if(tp != tags) {
#ifdef BOOTP_DEBUG
if(debug)
printf("%s %s\n", "dhcp.tags", tags);
#endif
setenv("dhcp.tags", tags, 1);
}
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E13jz66-0001aJ-00>
