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

📄 dhcp.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * dhcp.c	Functions to send/receive dhcp packets. * * Version:	$Id: dhcp.c,v 1.1 2008/04/20 14:51:25 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2008 The FreeRADIUS server project * Copyright 2008 Alan DeKok <aland@deployingradius.com> */#include	<freeradius-devel/ident.h>RCSID("$Id: dhcp.c,v 1.1 2008/04/20 14:51:25 aland Exp $")#include <freeradius-devel/libradius.h>#include <freeradius-devel/udpfromto.h>#include <freeradius-devel/dhcp.h>#ifdef WITH_DHCP#define DHCP_CHADDR_LEN	(16)#define DHCP_SNAME_LEN	(64)#define DHCP_FILE_LEN	(128)#define DHCP_VEND_LEN	(308)#define DHCP_OPTION_MAGIC_NUMBER (0x63825363)typedef struct dhcp_packet_t {	uint8_t		opcode;	uint8_t		htype;	uint8_t		hlen;	uint8_t		hops;	uint32_t	xid;	/* 4 */	uint16_t	secs;	/* 8 */	uint16_t	flags;	uint32_t	ciaddr;	/* 12 */	uint32_t	yiaddr;	/* 16 */	uint32_t	siaddr;	/* 20 */	uint32_t	giaddr;	/* 24 */	uint8_t		chaddr[DHCP_CHADDR_LEN]; /* 28 */	char		sname[DHCP_SNAME_LEN]; /* 44 */	char		file[DHCP_FILE_LEN]; /* 108 */	uint32_t	option_format; /* 236 */	uint8_t		options[DHCP_VEND_LEN];} dhcp_packet_t;/* *	INADDR_ANY : 68 -> INADDR_BROADCAST : 67	DISCOVER *	INADDR_BROADCAST : 68 <- SERVER_IP : 67		OFFER *	INADDR_ANY : 68 -> INADDR_BROADCAST : 67	REQUEST *	INADDR_BROADCAST : 68 <- SERVER_IP : 67		ACK */static const char *dhcp_header_names[] = {	"DHCP-Opcode",	"DHCP-Hardware-Type",	"DHCP-Hardware-Address-Length",	"DHCP-Hop-Count",	"DHCP-Transaction-Id",	"DHCP-Number-of-Seconds",	"DHCP-Flags",	"DHCP-Client-IP-Address",	"DHCP-Your-IP-Address",	"DHCP-Server-IP-Address",	"DHCP-Gateway-IP-Address",	"DHCP-Client-Hardware-Address",	"DHCP-Server-Host-Name",	"DHCP-Boot-Filename",	NULL};static const char *dhcp_message_types[] = {	"invalid",	"DHCP-Discover",	"DHCP-Offer",	"DHCP-Request",	"DHCP-Decline",	"DHCP-Ack",	"DHCP-NAK",	"DHCP-Release",	"DHCP-Inform",	"DHCP-Force-Renew",};static int dhcp_header_sizes[] = {	1, 1, 1, 1,	4, 2, 2, 4,	4, 4, 4,	DHCP_CHADDR_LEN,	DHCP_SNAME_LEN,	DHCP_FILE_LEN};/* *	Some clients silently ignore responses less than 300 bytes. */#define MIN_PACKET_SIZE (244)#define DEFAULT_PACKET_SIZE (576)#define MAX_PACKET_SIZE (1500 - 40)/* *	DHCPv4 is only for IPv4.  Broadcast only works if udpfromto is *	defined. */RADIUS_PACKET *fr_dhcp_recv(int sockfd){	uint32_t		magic;	struct sockaddr_storage	src;	struct sockaddr_storage	dst;	socklen_t		sizeof_src = sizeof(src);	socklen_t	        sizeof_dst = sizeof(dst);	RADIUS_PACKET		*packet;	memset(&src, 0, sizeof_src);	memset(&dst, 0, sizeof_dst);	packet = rad_alloc(0);	if (!packet) return NULL;	memset(packet, 0, sizeof(packet));	packet->data = malloc(MAX_PACKET_SIZE);	if (!packet->data) {		rad_free(&packet);		return NULL;	}	packet->sockfd = sockfd;	packet->data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,				    (struct sockaddr *)&src, &sizeof_src);	if (packet->data_len <= 0) {		fprintf(stderr, "Failed reading DHCP socket: %s", strerror(errno));		rad_free(&packet);		return NULL;	}	if (packet->data_len < MIN_PACKET_SIZE) {		fprintf(stderr, "DHCP packet is too small (%d < %d)",		      packet->data_len, MIN_PACKET_SIZE);		rad_free(&packet);		return NULL;	}	if (packet->data[0] != 1) {		fprintf(stderr, "Cannot receive DHCP server messages");		rad_free(&packet);		return NULL;	}	if (packet->data[1] != 1) {		fprintf(stderr, "DHCP can only receive ethernet requests, not type %02x",		      packet->data[1]);		rad_free(&packet);		return NULL;	}	if (packet->data[2] != 6) {		fprintf(stderr, "Ethernet HW length is wrong length %d\n",			packet->data[2]);		rad_free(&packet);		return NULL;	}	memcpy(&magic, packet->data + 236, 4);	magic = ntohl(magic);	if (magic != DHCP_OPTION_MAGIC_NUMBER) {		fprintf(stderr, "Cannot do BOOTP\n");		rad_free(&packet);		return NULL;	}	/*	 *	Create unique keys for the packet.	 */	memcpy(&magic, packet->data + 4, 4);	packet->id = ntohl(magic);	/*	 *	Check that it's a known packet type.	 */	if ((packet->data[240] != 53) ||	    (packet->data[241] != 1) ||	    (packet->data[242] == 0) ||	    (packet->data[242] >= 8)) {		fprintf(stderr, "Unknown, or badly formatted DHCP packet\n");		rad_free(&packet);		return NULL;	}	/*	 *	Create a unique vector from the MAC address and the	 *	DHCP opcode.  This is a hack for the RADIUS	 *	infrastructure in the rest of the server.	 *	 *	Note: packet->data[2] == 6, which is smaller than	 *	sizeof(packet->vector)	 *	 *	FIXME:  Look for client-identifier in packet,	 *      and use that, too?	 */	memset(packet->vector, 0, sizeof(packet->vector));	memcpy(packet->vector, packet->data + 28, packet->data[2]);	packet->vector[packet->data[2]] = packet->data[242];	/*	 *	FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1	 *	FIXME: for OFFER / ACK       : src_port = dst_port - 1	 */	packet->code = PW_DHCP_OFFSET | packet->data[242];	/*	 *	Unique keys are xid, client mac, and client ID?	 */	/*	 *	FIXME: More checks, like DHCP packet type?	 */	{		struct sockaddr_in	*s4;		struct sockaddr_storage si;		socklen_t si_len = sizeof(si);		/*		 *	This should never fail...		 */		getsockname(sockfd, (struct sockaddr *) &si, &si_len);		s4 = (struct sockaddr_in *)&src;		packet->src_ipaddr.af = AF_INET;		packet->src_ipaddr.ipaddr.ip4addr = s4->sin_addr;		packet->src_port = ntohs(s4->sin_port);		s4 = (struct sockaddr_in *)&si;		packet->dst_ipaddr.af = AF_INET;		packet->dst_ipaddr.ipaddr.ip4addr = s4->sin_addr;		packet->dst_port = ntohs(s4->sin_port);	}	if (librad_debug > 1) {		char type_buf[64];		const char *name = type_buf;		char src_ip_buf[256], dst_ip_buf[256];				if ((packet->code >= PW_DHCP_DISCOVER) &&		    (packet->code <= PW_DHCP_INFORM)) {			name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];		} else {			snprintf(type_buf, sizeof(type_buf), "%d",				 packet->code - PW_DHCP_OFFSET);		}		printf("Received %s of id %u from %s:%d to %s:%d\n",		       name, (unsigned int) packet->id,		       inet_ntop(packet->src_ipaddr.af,				 &packet->src_ipaddr.ipaddr,				 src_ip_buf, sizeof(src_ip_buf)),		       packet->src_port,		       inet_ntop(packet->dst_ipaddr.af,				 &packet->dst_ipaddr.ipaddr,				 dst_ip_buf, sizeof(dst_ip_buf)),		       packet->dst_port);		fflush(stdout);	}	return packet;}/* *	Send a DHCP packet. */int fr_dhcp_send(RADIUS_PACKET *packet){	struct sockaddr_storage	dst;	struct sockaddr_storage	src;	socklen_t		sizeof_dst = sizeof(dst);	socklen_t		sizeof_src = sizeof(src);	memset(&src, 0, sizeof(src));	memset(&dst, 0, sizeof(dst));	/*	 *	Only IPv4 is supported.	 */	{		struct sockaddr_in	*s4;		s4 = (struct sockaddr_in *)&dst;		sizeof_dst = sizeof(struct sockaddr_in);		s4->sin_family = AF_INET;		s4->sin_addr = packet->dst_ipaddr.ipaddr.ip4addr;		s4->sin_port = htons(packet->dst_port);		s4 = (struct sockaddr_in *)&src;		sizeof_src = sizeof(struct sockaddr_in);		s4->sin_family = AF_INET;		s4->sin_addr = packet->src_ipaddr.ipaddr.ip4addr;		s4->sin_port = htons(packet->src_port);	}	/*	 *	Assume that the packet is encoded before sending it.	 */	return sendto(packet->sockfd, packet->data, packet->data_len, 0,		      (struct sockaddr *)&dst, sizeof_dst);}int fr_dhcp_decode(RADIUS_PACKET *packet){	int i;	ssize_t total;	uint8_t *p;	uint32_t giaddr;	VALUE_PAIR *head, *vp, **tail;	VALUE_PAIR *maxms, *mtu;	char buffer[2048];	head = NULL;	tail = &head;	p = packet->data;		if ((librad_debug > 2) && fr_log_fp) {		for (i = 0; i < packet->data_len; i++) {			if ((i & 0x0f) == 0x00) fprintf(stderr, "%d: ", i);			fprintf(fr_log_fp, "%02x ", packet->data[i]);			if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");		}		fprintf(fr_log_fp, "\n");	}	if (packet->data[1] != 1) {		fprintf(stderr, "Packet is not Ethernet: %u\n",		      packet->data[1]);		return -1;	}	/*	 *	Decode the header.	 */	for (i = 0; i < 14; i++) {		vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);		if (!vp) {			fprintf(stderr, "Parse error %s\n", librad_errstr);			pairfree(&head);			return -1;		}		if ((i == 11) && 		    (packet->data[1] == 1) &&		    (packet->data[2] == 6)) {			vp->type = PW_TYPE_ETHERNET;		}		switch (vp->type) {		case PW_TYPE_BYTE:			vp->vp_integer = p[0];			vp->length = 1;			break;					case PW_TYPE_SHORT:			vp->vp_integer = (p[0] << 8) | p[1];			vp->length = 2;			break;					case PW_TYPE_INTEGER:			memcpy(&vp->vp_integer, p, 4);			vp->vp_integer = ntohl(vp->vp_integer);			vp->length = 4;			break;					case PW_TYPE_IPADDR:			memcpy(&vp->vp_ipaddr, p, 4);			vp->length = 4;			break;					case PW_TYPE_STRING:			memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);			vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';			vp->length = strlen(vp->vp_strvalue);			if (vp->length == 0) {				pairfree(&vp);			}			break;					case PW_TYPE_OCTETS:			memcpy(vp->vp_octets, p, packet->data[2]);			vp->length = packet->data[2];			break;					case PW_TYPE_ETHERNET:			memcpy(vp->vp_ether, p, packet->data[2]);			vp->length = packet->data[2];			break;					default:			fprintf(stderr, "BAD TYPE %d\n", vp->type);			pairfree(&vp);			break;		}		p += dhcp_header_sizes[i];		if (!vp) continue;				if (librad_debug > 1) {			vp_prints(buffer, sizeof(buffer), vp);			fprintf(stderr, "\t%s\n", buffer);		}		*tail = vp;		tail = &vp->next;	}		/*	 *	Loop over the options.	 */	p = packet->data + 240;	total = packet->data_len - 240;	while (total > 0) {		int num_entries, alen;		DICT_ATTR *da;		if (*p == 0) break;		if (*p == 255) break; /* end of options signifier */		if (p[1] >= 253) {			fprintf(stderr, "Attribute too long %u %u\n",			      p[0], p[1]);			goto do_next;		}						da = dict_attrbyvalue(DHCP2ATTR(p[0]));		if (!da) {			fprintf(stderr, "Attribute not in our dictionary: %u\n",			      p[0]);		do_next:			total -= 2;			total -= p[1];			p += p[1];			p += 2;			continue;		}		vp = NULL;		num_entries = 1;		alen = p[1];		p += 2;		if (da->flags.array) {			switch (da->type) {			case PW_TYPE_BYTE:				num_entries = alen;				alen = 1;				break;			case PW_TYPE_SHORT:				if ((alen & 0x01) != 0) goto raw;				num_entries = alen / 2;				alen = 2;				break;			case PW_TYPE_IPADDR:			case PW_TYPE_INTEGER:			case PW_TYPE_DATE:				if ((alen & 0x03) != 0) goto raw;				num_entries = alen / 4;				alen = 4;				break;			default:				break; /* really an internal sanity failure */			}		} else {			num_entries = 1;			switch (da->type) {			case PW_TYPE_BYTE:				if (alen != 1) goto raw;				break;			case PW_TYPE_SHORT:				if (alen != 2) goto raw;				break;			case PW_TYPE_IPADDR:			case PW_TYPE_INTEGER:			case PW_TYPE_DATE:				if (alen != 4) goto raw;				break;			default:				break;			}		}		for (i = 0; i < num_entries; i++) {			vp = pairmake(da->name, NULL, T_OP_EQ);			if (!vp) {				fprintf(stderr, "Cannot build attribute %s\n",					librad_errstr);				pairfree(&head);				return -1;			}			/*			 *	Hacks for ease of use.			 */			if ((da->attr == DHCP2ATTR(0x3d)) &&			    !da->flags.array &&			    (alen == 7) && (*p == 1) && (num_entries == 1)) {				vp->type = PW_TYPE_ETHERNET;				memcpy(vp->vp_octets, p + 1, 6);			} else				switch (vp->type) {				case PW_TYPE_BYTE:					vp->vp_integer = p[0];					break;								case PW_TYPE_SHORT:					vp->vp_integer = (p[0] << 8) | p[1];					break;				case PW_TYPE_INTEGER:					memcpy(&vp->vp_integer, p, 4);					vp->vp_integer = ntohl(vp->vp_integer);					break;				case PW_TYPE_IPADDR:					memcpy(&vp->vp_ipaddr, p , 4);					vp->length = 4;					break;				case PW_TYPE_STRING:					memcpy(vp->vp_strvalue, p , alen);					vp->vp_strvalue[alen] = '\0';					break;				raw:					vp = pairmake(da->name, NULL, T_OP_EQ);					if (!vp) {						fprintf(stderr, "Cannot build attribute %s\n", librad_errstr);						pairfree(&head);						return -1;					}					vp->type = PW_TYPE_OCTETS;								case PW_TYPE_OCTETS:					memcpy(vp->vp_octets, p, alen);					break;								default:					fprintf(stderr, "Internal sanity check %d %d\n", vp->type, __LINE__);					pairfree(&vp);					break;				} /* switch over type */							vp->length = alen;			if (librad_debug > 1) {				vp_prints(buffer, sizeof(buffer), vp);				fprintf(stderr, "\t%s\n", buffer);			}			*tail = vp;			tail = &vp->next;			p += alen;		} /* loop over array entries */				total -= 2;		total -= (alen * num_entries);	}	/*	 *	If DHCP request, set ciaddr to zero.	 */	/*	 *	Set broadcast flag for broken vendors, but only if	 *	giaddr isn't set.	 */	memcpy(&giaddr, packet->data + 24, sizeof(giaddr));

⌨️ 快捷键说明

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