⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcpd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <u.h>#include <libc.h>#include <ip.h>#include <bio.h>#include <ndb.h>#include "dat.h"////	ala rfc2131//typedef struct Req Req;struct Req{	int	fd;			/* for reply */	Bootp	*bp;	OUdphdr	*up;	uchar	*e;			/* end of received message */	uchar	*p;			/* options pointer */	uchar	*max;			/* max end of reply */	/* expanded to v6 */	uchar	ciaddr[IPaddrlen];	uchar	giaddr[IPaddrlen];	/* parsed options */	int	p9request;		/* true if this is a bootp with plan9 options */	int	genrequest;		/* true if this is a bootp with generic options */	int	dhcptype;		/* dhcp message type */	int	leasetime;		/* dhcp lease */	uchar	ip[IPaddrlen];		/* requested address */	uchar	server[IPaddrlen];	/* server address */	char	msg[ERRMAX];		/* error message */	char	vci[32];		/* vendor class id */	char	*id;			/* client id */	uchar	requested[32];		/* requested params */	uchar	vendorclass[32];	char	cputype[32-3];	Info	gii;			/* about target network */	Info	ii;			/* about target system */	int	staticbinding;	uchar buf[2*1024];		/* message buffer */};#define TFTP "/lib/tftpd"char	*blog = "ipboot";char	mysysname[64];Ipifc	*ipifcs;int	debug;int	nobootp;long	now;int	slowstat, slowdyn;char	net[256];int	pptponly;	// only answer request that came from the pptp serverint	mute, mutestat;int	minlease = MinLease;ulong	start;/* option magic */char plan9opt[4] = { 'p', '9', ' ', ' ' };char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 };/* well known addresses */uchar zeros[Maxhwlen];/* option debug buffer */char optbuf[1024];char *op;char *oe = optbuf + sizeof(optbuf);char *optname[256] ={[OBend]			"end",[OBpad]			"pad",[OBmask]		"mask",[OBtimeoff]		"timeoff",[OBrouter]		"router",[OBtimeserver]		"time",[OBnameserver]		"name",[OBdnserver]		"dns",[OBlogserver]		"log",[OBcookieserver]	"cookie",[OBlprserver]		"lpr",[OBimpressserver]	"impress",[OBrlserver]		"rl",[OBhostname]		"host",[OBbflen]		"bflen",[OBdumpfile]		"dumpfile",[OBdomainname]		"dom",[OBswapserver]		"swap",[OBrootpath]		"rootpath",[OBextpath]		"extpath",[OBipforward]		"ipforward",[OBnonlocal]		"nonlocal",[OBpolicyfilter]	"policyfilter",[OBmaxdatagram]		"maxdatagram",[OBttl]			"ttl",[OBpathtimeout]		"pathtimeout",[OBpathplateau]		"pathplateau",[OBmtu]			"mtu",[OBsubnetslocal]	"subnetslocal",[OBbaddr]		"baddr",[OBdiscovermask]	"discovermask",[OBsupplymask]		"supplymask",[OBdiscoverrouter]	"discoverrouter",[OBrsserver]		"rsserver",[OBstaticroutes]	"staticroutes",[OBtrailerencap]	"trailerencap",[OBarptimeout]		"arptimeout",[OBetherencap]		"etherencap",[OBtcpttl]		"tcpttl",[OBtcpka]		"tcpka",[OBtcpkag]		"tcpkag",[OBnisdomain]		"nisdomain",[OBniserver]		"niserver",[OBntpserver]		"ntpserver",[OBvendorinfo]		"vendorinfo",[OBnetbiosns]		"NBns",[OBnetbiosdds]		"NBdds",[OBnetbiostype]		"NBtype",[OBnetbiosscope]	"NBscope",[OBxfontserver]		"xfont",[OBxdispmanager]	"xdisp",[OBnisplusdomain]	"NPdomain",[OBnisplusserver]	"NP",[OBhomeagent]		"homeagent",[OBsmtpserver]		"smtp",[OBpop3server]		"pop3",[OBnntpserver]		"nntp",[OBwwwserver]		"www",[OBfingerserver]	"finger",[OBircserver]		"ircserver",[OBstserver]		"stserver",[OBstdaserver]		"stdaserver",/* dhcp options */[ODipaddr]		"ip",[ODlease]		"leas",[ODoverload]		"overload",[ODtype]		"typ",[ODserverid]		"sid",[ODparams]		"params",[ODmessage]		"message",[ODmaxmsg]		"maxmsg",[ODrenewaltime]		"renewaltime",[ODrebindingtime]	"rebindingtime",[ODvendorclass]		"vendorclass",[ODclientid]		"cid",[ODtftpserver]		"tftpserver",[ODbootfile]		"bf",};void	addropt(Req*, int, uchar*);void	addrsopt(Req*, int, uchar**, int);void	arpenter(uchar*, uchar*);void	bootp(Req*);void	byteopt(Req*, int, uchar);void	dhcp(Req*);void	fatal(int, char*, ...);void	hexopt(Req*, int, char*);void	longopt(Req*, int, long);void	maskopt(Req*, int, uchar*);void	miscoptions(Req*, uchar*);int	openlisten(char *net);void	parseoptions(Req*);void	proto(Req*, int);void	rcvdecline(Req*);void	rcvdiscover(Req*);void	rcvinform(Req*);void	rcvrelease(Req*);void	rcvrequest(Req*);char*	readsysname(void);void	remrequested(Req*, int);void	sendack(Req*, uchar*, int, int);void	sendnak(Req*, char*);void	sendoffer(Req*, uchar*, int);void	stringopt(Req*, int, char*);void	termopt(Req*);int	validip(uchar*);void	vectoropt(Req*, int, uchar*, int);void	warning(int, char*, ...);void	logdhcp(Req*);void	logdhcpout(Req *, char *);int	readlast(int, uchar*, int);voidtimestamp(char *tag){	ulong t;	t = nsec()/1000;	syslog(0, blog, "%s %lud", tag, t - start);}voidusage(void){	fprint(2, "usage: dhcp [-dmsnp] [-f directory] [-x netmtpt] [-M minlease] addr n [addr n ...]\n");	exits("usage");}voidmain(int argc, char **argv){	int i, n, fd;	char *p;	uchar ip[IPaddrlen];	Req r;	setnetmtpt(net, sizeof(net), nil);	fmtinstall('E', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('V', eipfmt);	fmtinstall('M', eipfmt);	ARGBEGIN {	case 'm':		mute = 1;		break;	case 'd':		debug = 1;		break;	case 'f':		p = ARGF();		if(p == nil)			usage();		ndbfile = p;		break;	case 's':		slowstat = 1;		break;	case 'S':		slowdyn = 1;		break;	case 'n':		nobootp = 1;		break;	case 'p':		pptponly = 1;		break;	case 'r':		mutestat = 1;		break;	case 'x':		p = ARGF();		if(p == nil)			usage();		setnetmtpt(net, sizeof(net), p);		break;	case 'M':		p = ARGF();		if(p == nil)			usage();		minlease = atoi(p);		if(minlease <= 0)			minlease = MinLease;		break;	} ARGEND;	while(argc > 1){		parseip(ip, argv[0]);		if(!validip(ip))			usage();		n = atoi(argv[1]);		if(n <= 0)			usage();		initbinding(ip, n);		argc -= 2;		argv += 2;	}	/* for debugging */	for(i = 0; i < 256; i++)		if(optname[i] == 0)			optname[i] = smprint("%d", i);	/* what is my name? */	p = readsysname();	strcpy(mysysname, p);	/* put process in background */	if(!debug) switch(rfork(RFNOTEG|RFPROC|RFFDG)) {	case -1:		fatal(1, "fork");	case 0:		break;	default:		exits(0);	}	chdir(TFTP);	fd = openlisten(net);	for(;;){		memset(&r, 0, sizeof(r));		r.fd = fd;		n = readlast(r.fd, r.buf, sizeof(r.buf));		if(n < OUdphdrsize)			fatal(1, "error reading requests");		start = nsec()/1000;		op = optbuf;		*op = 0;		proto(&r, n);		if(r.id != nil)			free(r.id);	}}voidproto(Req *rp, int n){	uchar relip[IPaddrlen];	char buf[64];	now = time(0);	rp->e = rp->buf + n;	rp->bp = (Bootp*)rp->buf;	rp->up = (OUdphdr*)rp->buf;	rp->max = rp->buf + OUdphdrsize + MINSUPPORTED - IPUDPHDRSIZE;	rp->p = rp->bp->optdata;	v4tov6(rp->giaddr, rp->bp->giaddr);	v4tov6(rp->ciaddr, rp->bp->ciaddr);	if(pptponly && rp->bp->htype != 0)		return;	ipifcs = readipifc(net, ipifcs, -1);	if(validip(rp->giaddr))		ipmove(relip, rp->giaddr);	else if(validip(rp->up->raddr))		ipmove(relip, rp->up->raddr);	else		ipmove(relip, rp->up->laddr);	if(rp->e < (uchar*)rp->bp->sname){		warning(0, "packet too short");		return;	}	if(rp->bp->op != Bootrequest){		warning(0, "not bootrequest");		return;	}	if(rp->e >= rp->bp->optdata){		if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0)			rp->p9request = 1;		if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) {			rp->genrequest = 1;			parseoptions(rp);		}	}	rp->p = rp->bp->optdata;	/*  If no id is specified, make one from the hardware address	 *  of the target.  We assume all zeros is not a hardware address	 *  which could be a mistake.	 */	if(rp->id == nil){		if(rp->bp->hlen > Maxhwlen){			warning(0, "hlen %d", rp->bp->hlen);			return;		}		if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){			warning(0, "no chaddr");			return;		}		sprint(buf, "hwa%2.2ux_", rp->bp->htype);		rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen);	}	/* info about gateway */	if(lookupip(relip, &rp->gii, 1) < 0){		warning(0, "lookupip failed");		return;	}	/* info about target system */	if(lookup(rp->bp, &rp->ii, &rp->gii) == 0)		if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0)			rp->staticbinding = 1;	if(rp->dhcptype)		dhcp(rp);	else		bootp(rp);timestamp("done");}static voidslowdelay(Req *rp){	if(slowstat && rp->staticbinding || slowdyn && !rp->staticbinding)		sleep(2000);}voiddhcp(Req *rp){	logdhcp(rp);	switch(rp->dhcptype){	case Discover:		slowdelay(rp);		rcvdiscover(rp);		break;	case Request:		rcvrequest(rp);		break;	case Decline:		rcvdecline(rp);		break;	case Release:		rcvrelease(rp);		break;	case Inform:		rcvinform(rp);		break;	}}voidrcvdiscover(Req *rp){	Binding *b, *nb;	if(rp->staticbinding){		sendoffer(rp, rp->ii.ipaddr, (StaticLease > minlease ? StaticLease : minlease));		return;	}	/*	 *  first look for an outstanding offer	 */	b = idtooffer(rp->id, &rp->gii);	/*	 * rfc2131 says:	 *   If an address is available, the new address	 *   SHOULD be chosen as follows:	 *	 *      o The client's current address as recorded in the client's current	 *        binding, ELSE	 *	 *      o The client's previous address as recorded in the client's (now	 *        expired or released) binding, if that address is in the server's	 *        pool of available addresses and not already allocated, ELSE	 *	 *      o The address requested in the 'Requested IP Address' option, if that	 *        address is valid and not already allocated, ELSE	 *	 *      o A new address allocated from the server's pool of available	 *        addresses; the address is selected based on the subnet from which	 *        the message was received (if 'giaddr' is 0) or on the address of	 *        the relay agent that forwarded the message ('giaddr' when not 0).	 */	if(b == nil){		b = idtobinding(rp->id, &rp->gii, 1);		if(b && b->boundto && strcmp(b->boundto, rp->id) != 0)		if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){			nb = iptobinding(rp->ip, 0);			if(nb && nb->lease < now)				b = nb;		}	}	if(b == nil){		warning(0, "!Discover(%s via %I): no binding %I",			rp->id, rp->gii.ipaddr, rp->ip);		return;	}	mkoffer(b, rp->id, rp->leasetime);	sendoffer(rp, b->ip, b->offer);}voidrcvrequest(Req *rp){	Binding *b;	if(validip(rp->server)){		/* this is a reply to an offer - SELECTING */		/* check for hard assignment */		if(rp->staticbinding){			if(forme(rp->server))				sendack(rp, rp->ii.ipaddr, (StaticLease > minlease ? StaticLease : minlease), 1);			else				warning(0, "!Request(%s via %I): for server %I not me",					rp->id, rp->gii.ipaddr, rp->server);			return;		}		b = idtooffer(rp->id, &rp->gii);		/* if we don't have an offer, nak */		if(b == nil){			warning(0, "!Request(%s via %I): no offer",				rp->id, rp->gii.ipaddr);			if(forme(rp->server))				sendnak(rp, "no offer for you");			return;		}		/* if not for me, retract offer */		if(!forme(rp->server)){			b->expoffer = 0;			warning(0, "!Request(%s via %I): for server %I not me",				rp->id, rp->gii.ipaddr, rp->server);			return;		}		/*		 *  if the client is confused about what we offered, nak.		 *  client really shouldn't be specifying this when selecting		 */		if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){			warning(0, "!Request(%s via %I): requests %I, not %I",				rp->id, rp->gii.ipaddr, rp->ip, b->ip);			sendnak(rp, "bad ip address option");			return;		}		if(commitbinding(b) < 0){			warning(0, "!Request(%s via %I): can't commit %I",				rp->id, rp->gii.ipaddr, b->ip);			sendnak(rp, "can't commit binding");			return;		}		sendack(rp, b->ip, b->offer, 1);	} else if(validip(rp->ip)){		/*		 *  checking address/net - INIT-REBOOT		 *		 *  This is a rebooting client that remembers its old		 *  address.		 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -