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

📄 dhcp.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (giaddr == htonl(INADDR_ANY)) {		/*		 *	DHCP Opcode is request		 */		vp = pairfind(head, DHCP2ATTR(256));		if (vp && vp->lvalue == 3) {			/*			 *	Vendor is "MSFT 98"			 */			vp = pairfind(head, DHCP2ATTR(63));			if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {				vp = pairfind(head, DHCP2ATTR(262));				/*				 *	Reply should be broadcast.				 */				if (vp) vp->lvalue |= 0x8000;				packet->data[10] |= 0x80;						}		}	}	/*	 *	FIXME: Nuke attributes that aren't used in the normal	 *	header for discover/requests.	 */	packet->vps = head;	/*	 *	Client can request a LARGER size, but not a smaller	 *	one.  They also cannot request a size larger than MTU.	 */	maxms = pairfind(packet->vps, DHCP2ATTR(57));	mtu = pairfind(packet->vps, DHCP2ATTR(26));	if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {		fprintf(stderr, "DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");		return -1;	}	if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {		fprintf(stderr, "DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");		maxms->vp_integer = DEFAULT_PACKET_SIZE;	}	if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {		fprintf(stderr, "DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");		maxms->vp_integer = mtu->vp_integer;	}	if (librad_debug) fflush(stdout);	return 0;}static int attr_cmp(const void *one, const void *two){	const VALUE_PAIR * const *a = one;	const VALUE_PAIR * const *b = two;	/*	 *	DHCP-Message-Type is first, for simplicity.	 */	if (((*a)->attribute == DHCP2ATTR(53)) &&	    (*b)->attribute != DHCP2ATTR(53)) return -1;	/*	 *	Relay-Agent is last	 */	if (((*a)->attribute == DHCP2ATTR(82)) &&	    (*b)->attribute != DHCP2ATTR(82)) return +1;	return ((*a)->attribute - (*b)->attribute);}static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, size_t room){	size_t length;	uint32_t lvalue;	/*	 *	FIXME: Check room!	 */	room = room;		/* -Wunused */	/*	 *	Search for all attributes of the same	 *	type, and pack them into the same	 *	attribute.	 */	switch (vp->type) {	case PW_TYPE_BYTE:		length = 1;		*p = vp->vp_integer & 0xff;		break;			case PW_TYPE_SHORT:		length = 2;		p[0] = (vp->vp_integer >> 8) & 0xff;		p[1] = vp->vp_integer & 0xff;		break;			case PW_TYPE_INTEGER:		length = 4;		lvalue = htonl(vp->vp_integer);		memcpy(p, &lvalue, 4);		break;			case PW_TYPE_IPADDR:		length = 4;		memcpy(p, &vp->vp_ipaddr, 4);		break;			case PW_TYPE_ETHERNET:		length = 6;		memcpy(p, &vp->vp_ether, 6);		break;			case PW_TYPE_STRING:		memcpy(p, vp->vp_strvalue, vp->length);		length = vp->length;		break;			case PW_TYPE_OCTETS:		memcpy(p, vp->vp_octets, vp->length);		length = vp->length;		break;			default:		fprintf(stderr, "BAD TYPE2 %d\n", vp->type);		length = 0;		break;	}	return length;}int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original){	int i, num_vps;	uint8_t *p;	VALUE_PAIR *vp;	uint32_t lvalue, mms;	size_t dhcp_size, length;	dhcp_packet_t *dhcp;	char buffer[1024];	if (packet->data) return 0;	packet->data = malloc(MAX_PACKET_SIZE);	if (!packet->data) return -1;	packet->data_len = MAX_PACKET_SIZE;	if (packet->code == 0) packet->code = PW_DHCP_NAK;	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("Sending %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);	}	p = packet->data;	mms = DEFAULT_PACKET_SIZE; /* maximum message size */	/*	 *	Client can request a LARGER size, but not a smaller	 *	one.  They also cannot request a size larger than MTU.	 */	vp = pairfind(original->vps, DHCP2ATTR(57));	if (vp && (vp->vp_integer > mms)) {		mms = vp->vp_integer;				if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;	}	/*	 *	RFC 3118: Authentication option.	 */	vp = pairfind(packet->vps, DHCP2ATTR(90));	if (vp) {		if (vp->length < 2) {			memset(vp->vp_octets + vp->length, 0,			       2 - vp->length);			vp->length = 2;		}		if (vp->length < 3) {			struct timeval tv;			gettimeofday(&tv, NULL);			vp->vp_octets[2] = 0;			timeval2ntp(&tv, vp->vp_octets + 3);			vp->length = 3 + 8;		}		/*		 *	Configuration token (clear-text token)		 */		if (vp->vp_octets[0] == 0) {			VALUE_PAIR *pass;			vp->vp_octets[1] = 0;			pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);			if (pass) {				length = pass->length;				if ((length + 11) > sizeof(vp->vp_octets)) {					length -= ((length + 11) - sizeof(vp->vp_octets));				}				memcpy(vp->vp_octets + 11, pass->vp_strvalue,				       length);				vp->length = length + 11;			} else {				vp->length = 11 + 8;				memset(vp->vp_octets + 11, 8, 0);				vp->length = 11 + 8;			}		} else {	/* we don't support this type! */			fprintf(stderr, "DHCP-Authentication %d unsupported\n",				vp->vp_octets[0]);		}	}	if (!original) {		*p++ = 1;	/* client message */	} else {		*p++ = 2;	/* server message */	}	*p++ = 1;		/* hardware type = ethernet */	*p++ = original->data[2];	*p++ = 0;		/* hops */	if (!original) {	/* Xid */		lvalue = fr_rand();		memcpy(p, &lvalue, 4);	} else {		memcpy(p, original->data + 4, 4);	}	p += 4;	memset(p, 0, 2);	/* secs are zero */	p += 2;	memcpy(p, original->data + 10, 6); /* copy flags && ciaddr */	p += 6;	/*	 *	Set client IP address.	 */	vp = pairfind(packet->vps, DHCP2ATTR(264)); /* Your IP address */	if (vp) {		lvalue = vp->vp_ipaddr;	} else {		lvalue = htonl(INADDR_ANY);	}	memcpy(p, &lvalue, 4);	/* your IP address */	p += 4;	memset(p, 0, 4);	/* siaddr is zero */	p += 4;	memset(p, 0, 4);	/* gateway address is zero */	p += 4;	/*	 *	FIXME: allow it to send client packets.	 */	if (!original) {		librad_log("Need original to send response!");		return -1;	}	memcpy(p, original->data + 28, DHCP_CHADDR_LEN);	p += DHCP_CHADDR_LEN;	memset(p, 0, 192);	/* bootp legacy */	p += 192;	lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER); /* DHCP magic number */	memcpy(p, &lvalue, 4);	p += 4;	/*	 *	Print the header.	 */	if (librad_debug > 1) {		uint8_t *pp = p;		p = packet->data;		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);				return -1;			}						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);				break;							case PW_TYPE_OCTETS: /* only for Client HW Address */				memcpy(vp->vp_octets, p, packet->data[2]);				vp->length = packet->data[2];				break;							default:				fprintf(stderr, "Internal sanity check failed %d %d\n", vp->type, __LINE__);				pairfree(&vp);				break;			}						p += dhcp_header_sizes[i];						vp_prints(buffer, sizeof(buffer), vp);			fprintf(stderr, "\t%s\n", buffer);			pairfree(&vp);		}		/*		 *	Jump over DHCP magic number, response, etc.		 */		p = pp;	}	vp = pairfind(packet->vps, DHCP2ATTR(53));	if (vp && (vp->vp_integer != (packet->code - PW_DHCP_OFFSET))) {		fprintf(stderr, "Message-Type doesn't match! %d %d\n",			packet->code, vp->vp_integer);	}	pairdelete(&packet->vps, DHCP2ATTR(0x35));	/*	 *	Before packing the attributes, re-order them so that	 *	the array ones are all contiguous.  This simplifies	 *	the later code.	 */	num_vps = 0;	for (vp = packet->vps; vp != NULL; vp = vp->next) {		num_vps++;	}	if (num_vps > 1) {		VALUE_PAIR **array, **last;		array = malloc(num_vps * sizeof(VALUE_PAIR *));				i = 0;		for (vp = packet->vps; vp != NULL; vp = vp->next) {			array[i++] = vp;		}				/*		 *	Sort the attributes.		 */		qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *),		      attr_cmp);				last = &packet->vps;		for (i = 0; i < num_vps; i++) {			*last = array[i];			array[i]->next = NULL;			last = &(array[i]->next);		}		free(array);	}	p[0] = 0x35;		/* DHCP-Message-Type */	p[1] = 1;	p[2] = packet->code - PW_DHCP_OFFSET;	p += 3;	/*	 *	Pack in the attributes.	 */	vp = packet->vps;	while (vp) {		int num_entries = 1;				VALUE_PAIR *same;		uint8_t *plength, *pattr;		if (!IS_DHCP_ATTR(vp)) goto next;		if (((vp->attribute & 0xffff) > 255) &&		    (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;		length = vp->length;		for (same = vp->next; same != NULL; same = same->next) {			if (same->attribute != vp->attribute) break;			num_entries++;		}		/*		 *	For client-identifier		 */		if ((vp->type == PW_TYPE_ETHERNET) &&		    (vp->length == 6) &&		    (num_entries == 1)) {			vp->type = PW_TYPE_OCTETS;			memmove(vp->vp_octets + 1, vp->vp_octets, 6);			vp->vp_octets[0] = 1;		}		pattr = p;		*(p++) = vp->attribute & 0xff;		plength = p;		*(p++) = 0;	/* header isn't included in attr length */		if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {			*(p++) = DHCP_UNPACK_OPTION1(vp->attribute);			*(p++) = 0;			*plength = 2;		}		for (i = 0; i < num_entries; i++) {			if (librad_debug > 1) {				vp_prints(buffer, sizeof(buffer), vp);				fprintf(stderr, "\t%s\n", buffer);			}			length = fr_dhcp_vp2attr(vp, p, 0);			/*			 *	This will never happen due to FreeRADIUS			 *	limitations: sizeof(vp->vp_octets) < 255			 */			if (length > 255) {				fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);				break;			}			/*			 *	More than one attribute of the same type			 *	in a row: they are packed together			 *	into the same TLV.  If we overflow,			 *	go bananas!			 */			if ((*plength + length) > 255) {				fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);				break;			}						*plength += length;			p += length;			if (vp->next &&			    (vp->next->attribute == vp->attribute))				vp = vp->next;		} /* loop over num_entries */		if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {			plength[2] = plength[0] - 2;		}	next:		vp = vp->next;	}	p[0] = 0xff;		/* end of option option */	p[1] = 0x00;	p += 2;	dhcp_size = p - packet->data;	/*	 *	FIXME: if (dhcp_size > mms),	 *	  then we put the extra options into the "sname" and "file"	 *	  fields, AND set the "end option option" in the "options"	 *	  field.  We also set the "overload option",	 *	  and put options into the "file" field, followed by	 *	  the "sname" field.  Where each option is completely	 *	  enclosed in the "file" and/or "sname" field, AND	 *	  followed by the "end of option", and MUST be followed	 *	  by padding option.	 *	 *	Yuck.  That sucks...	 */	packet->data_len = dhcp_size;	packet->dst_ipaddr.af = AF_INET;	packet->src_ipaddr.af = AF_INET;	packet->dst_port = original->src_port;	packet->src_port = original->dst_port;	/*	 *	Note that for DHCP, we NEVER send the response to the	 *	source IP address of the request.  It may have	 *	traversed multiple relays, and we need to send the request	 *	to the relay closest to the client.	 *	 *	if giaddr, send to giaddr.	 *	if NAK, send broadcast packet	 *	if ciaddr, unicast to ciaddr	 *	if flags & 0x8000, broadcast (client request)	 *	if sent from 0.0.0.0, broadcast response	 *	unicast to client yiaddr	 */	/*	 *	FIXME: alignment issues.  We likely don't want to	 *	de-reference the packet structure directly..	 */	dhcp = (dhcp_packet_t *) original->data;	if (dhcp->giaddr != htonl(INADDR_ANY)) {		packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;	} else if (packet->code == PW_DHCP_NAK) {		packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);			} else if (dhcp->ciaddr != htonl(INADDR_ANY)) {		packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;	} else if ((dhcp->flags & 0x8000) != 0) {		packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);	} else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) {		packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);	} else {		packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr;	}	/*	 *	FIXME: This may set it to broadcast, which we don't	 *	want.  Instead, set it to the real address of the	 *	socket.	 */	packet->src_ipaddr = original->dst_ipaddr;	packet->sockfd = original->sockfd;	if (packet->data_len < DEFAULT_PACKET_SIZE) {		memset(packet->data + packet->data_len, 0,		       DEFAULT_PACKET_SIZE - packet->data_len);		packet->data_len = DEFAULT_PACKET_SIZE;	}	if ((librad_debug > 2) && fr_log_fp) {		for (i = 0; i < packet->data_len; i++) {			if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);			fprintf(fr_log_fp, "%02x ", packet->data[i]);			if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");		}		fprintf(fr_log_fp, "\n");	}	return 0;}#endif /* WITH_DHCP */

⌨️ 快捷键说明

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