Пример #1
0
Файл: dhcp.c Проект: nicboul/xia
char *dhcp_get_hostname(uint8_t *p, const uint8_t *z)
{
	journal_ftrace(__func__);

	struct dhcp_opt_hdr *h;
	char *dst, *src;
	uint8_t len;

	h = dhcp_get_option(p, z, DHCP_OPT_HOSTNAME);

	if (h == NULL)
		return NULL;

	len = h->length;
	h++;

	src = (char *)((uint8_t *)h);
	dst = calloc(1, len + 1);

	if (dst != NULL) {
		strncpy(dst, src, len);
		dst[len] = '\0';
		return dst;
	}

	return NULL;
}
Пример #2
0
Файл: dhcp.c Проект: nicboul/xia
char *dhcp_get_fqdn(uint8_t *p, const uint8_t *z)
{
	journal_ftrace(__func__);

	struct dhcp_opt_hdr *h;
	char *dst, *src;
	uint8_t len;

	h = dhcp_get_option(p, z, DHCP_OPT_FQDN);

	if (h == NULL || h->length <= DHCP_OPT_FQDN_FLAGS_LENGTH)
		return NULL;

	len = h->length - DHCP_OPT_FQDN_FLAGS_LENGTH;
	h++;

	src = (char *)((uint8_t *)h + DHCP_OPT_FQDN_FLAGS_LENGTH);
	dst = calloc(1, len + 1);

	if (dst != NULL) {
		strncpy(dst, src, len);
		dst[len] = '\0';
		return dst;
	}

	return NULL;
}
Пример #3
0
Файл: dhcp.c Проект: nicboul/xia
uint8_t dhcp_get_msgtype(uint8_t *p, const uint8_t *z)
{
	journal_ftrace(__func__);

	struct dhcp_opt_hdr *h;

	h = dhcp_get_option(p, z, DHCP_OPT_MSGTYPE);
	if (h == NULL || h->length != 1)
		return 0;

	return *(uint8_t *)++h;
}
Пример #4
0
static unsigned dhcp_number(const unsigned char *px, unsigned length, unsigned tag)
{
	unsigned i;
	unsigned result;
	const unsigned char *option;
	unsigned option_length;

	dhcp_get_option(px, length, tag, &option, &option_length);
	if (option_length == 0)
		return 0xFFFFFFFF;
	result = 0;
	for (i=0; i<option_length; i++)
		result = result * 256 + option[i];
	return result;
}
Пример #5
0
static uint8_t check_packet_type(struct dhcp_packet *packet)
{
	uint8_t *type;

	if (packet->hlen != ETH_ALEN)
		return 0;

	if (packet->op != BOOTREQUEST)
		return 0;

	type = dhcp_get_option(packet, DHCP_MESSAGE_TYPE);

	if (!type)
		return 0;

	if (*type < DHCP_MINTYPE)
		return 0;

	if (*type > DHCP_MAXTYPE)
		return 0;

	return *type;
}
Пример #6
0
static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
							gpointer user_data)
{
	GDHCPServer *dhcp_server = user_data;
	struct dhcp_packet packet;
	struct dhcp_lease *lease;
	uint32_t requested_nip = 0;
	uint8_t type, *server_id_option, *request_ip_option, *host_name;
	int re;

	GDHCPOptionType option_type;
	char *option_value;

	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
		dhcp_server->listener_watch = 0;
		return FALSE;
	}

	re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd);
	if (re < 0)
		return TRUE;

	type = check_packet_type(&packet);
	if (type == 0)
		return TRUE;

	server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID);
	if (server_id_option) {
		uint32_t server_nid = get_be32(server_id_option);

		if (server_nid != dhcp_server->server_nip)
			return TRUE;
	}

	request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP);
	if (request_ip_option)
		requested_nip = get_be32(request_ip_option);

	lease = find_lease_by_mac(dhcp_server, packet.chaddr);

	switch (type) {
	case DHCPDISCOVER:
		debug(dhcp_server, "Received DISCOVER");

		send_offer(dhcp_server, &packet, lease, requested_nip);
		break;
	case DHCPREQUEST:
		debug(dhcp_server, "Received REQUEST NIP %d",
							requested_nip);
		if (requested_nip == 0) {
			requested_nip = packet.ciaddr;
			if (requested_nip == 0)
				break;
		}

		if (lease && requested_nip == lease->lease_nip) {
			debug(dhcp_server, "Sending ACK");
			host_name =
				dhcp_get_option(&packet,
					 DHCP_HOST_NAME);
			option_type =
				dhcp_get_code_type(DHCP_HOST_NAME);
			option_value =
				malloc_option_value_string(host_name,
					 option_type);

			send_ACK(dhcp_server, &packet,
				lease->lease_nip);

			if (dhcp_server->save_ack_lease_func)
				dhcp_server->save_ack_lease_func(
					option_value,
					lease->lease_mac,
					lease->lease_nip);

			g_free(option_value);

			break;
		}

		if (server_id_option || !lease) {
			debug(dhcp_server, "Sending NAK");
			send_NAK(dhcp_server, &packet);
		}

		break;
	case DHCPDECLINE:
		debug(dhcp_server, "Received DECLINE");

		if (!server_id_option)
			break;

		if (!request_ip_option)
			break;

		if (!lease)
			break;

		if (requested_nip == lease->lease_nip)
			remove_lease(dhcp_server, lease);

		break;
	case DHCPRELEASE:
		debug(dhcp_server, "Received RELEASE");

		if (!server_id_option)
			break;

		if (!lease)
			break;

		if (packet.ciaddr == lease->lease_nip)
			lease_set_expire(dhcp_server, lease,
					time(NULL));
		break;
	case DHCPINFORM:
		debug(dhcp_server, "Received INFORM");
		send_inform(dhcp_server, &packet);
		break;
	}

	return TRUE;
}
Пример #7
0
int dhcp_option82_handle(struct sk_buff *skb, struct dhcp_packet *dhcp, dba_result_t *res)
{
	struct ethhdr *ethhdr = NULL;
	struct iphdr *iph = NULL;
	struct udphdr *udph = NULL;
	unsigned char *tail = NULL;
	
	if (unlikely(!skb || !dhcp || !res)) {
		return -1;
	}

	if ((DHCP_CLIENT_REQUEST == dhcp->op)
		&& (res->module_type & DHCP_OPTION82_KMOD)) {

		if (dba_option82_debug) {
			printk(KERN_DEBUG "skb->dev->name : %s\n", skb->dev->name);
			printPacketBuffer(skb->data, skb->len);
			printk(KERN_DEBUG "res->len : %d\n", res->len);
			printk(KERN_DEBUG "res->data : \n");
			printPacketBuffer((unsigned char *)res->data, res->len);
		}

		/* 253 = 2^8 - 2(option code len) */
		if (unlikely((res->len) > 255)) {
			log_error("dhcp option82 length %d: too large!\n", res->len);
			res->result |= DBA_ERROR;			
			return -1;
		}

		/* enlarge skb, pointer dhcp may change, so must recalculate */
		if (dba_enlarge_skb(skb, DBA_ALIGN4(res->len + 2))) {
			log_error("dhcp option82 expand skb failed!\n");
			res->result |= DBA_ERROR;
			return -1;
		}

		/* skb may change, so recalculate pointer */
		ethhdr = eth_hdr(skb);
		iph = (struct iphdr *)(ethhdr + 1);
		udph = (struct udphdr *)IPv4_NXT_HDR(iph);
		dhcp = (struct dhcp_packet *)(udph + 1);


		#if 0
		tail = skb_tail_pointer(skb);
		
		if (0xff == *((unsigned char *)(tail-1))) {
			/* append option82 */
			*(tail-1) = 82;	/* option 82 code */
			*tail = res->len;	/* option 82 length */
			
			memcpy(skb_put(skb, res->len+2)+1, res->data, res->len);

			tail = skb_tail_pointer(skb);
			*(tail-1) = 0xff; /* dhcp end option */

		} else {
			/* append option82 */
			*(tail) = 82;	/* option 82 code */
			*(tail+1) = res->len;	/* option 82 length */
			
			memcpy(skb_put(skb, res->len+2)+2, res->data, res->len);
			tail = skb_tail_pointer(skb);			
			*(tail-1) = 0xff; /* dhcp end option */
		}
		#else

		/* geti skb tail */
		tail = skb_tail_pointer(skb);
		/* get dhcp end option(0xff) */
		if (tail = dhcp_get_option(dhcp, 0xff, tail)) {
			skb_put(skb, res->len + 2);
			/* append option82 */
			*(tail) = 82;	/* option 82 code */
			*(tail + 1) = res->len;	/* option 82 length */
			memcpy(tail + 2, res->data, res->len);

			#if 0
			tail = skb_tail_pointer(skb);			
			*(tail-1) = 0xff; /* dhcp end option */
			#endif

			*(tail + 2 + res->len) = 0xff;/* dhcp end option added just behind option82 */
		} else {
			res->result |= DBA_ERROR;
			log_error("dhcp option82 cannot find option 255!\n");			
			return -1;
		}
		#endif
		
		/* recalculate ip length Checksum*/
		/*
		ethhdr = eth_hdr(skb);
		iph = (struct iphdr *)(ethhdr + 1);
		udph = (struct udphdr *)IPv4_NXT_HDR(iph);
		*/
		
		/* ip header length */
		iph->tot_len += (res->len + 2);

		/* ip checksum */
		iph->check = 0;
		iph->check = ip_fast_csum(iph, iph->ihl);

		/* recalculate udp Checksum length */
		udph->len += (res->len + 2);
		udph->check = 0;
		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udph->len,
			IPPROTO_UDP, csum_partial(udph, udph->len, 0));

		
		res->result |= DBA_HANDLED;
	}
	return 0;
}
Пример #8
0
static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
							gpointer user_data)
{
	GDHCPServer *dhcp_server = user_data;
	struct dhcp_packet packet;
	struct dhcp_lease *lease;
	uint32_t requested_nip = 0;
	uint8_t type, *server_id_option, *request_ip_option;
	int re;

	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
		dhcp_server->listener_watch = 0;
		return FALSE;
	}

	re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd);
	if (re < 0)
		return TRUE;

	type = check_packet_type(&packet);
	if (type == 0)
		return TRUE;

	server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID);
	if (server_id_option) {
		uint32_t server_nid = dhcp_get_unaligned(
					(uint32_t *) server_id_option);

		if (server_nid != dhcp_server->server_nip)
			return TRUE;
	}

	request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP);
	if (request_ip_option)
		requested_nip = dhcp_get_unaligned(
					(uint32_t *) request_ip_option);

	lease = find_lease_by_mac(dhcp_server, packet.chaddr);

	switch (type) {
		case DHCPDISCOVER:
			debug(dhcp_server, "Received DISCOVER");

			send_offer(dhcp_server, &packet, lease, requested_nip);
		break;
		case DHCPREQUEST:
			debug(dhcp_server, "Received REQUEST NIP %d",
							requested_nip);
			if (requested_nip == 0) {
				requested_nip = packet.ciaddr;
				if (requested_nip == 0)
					break;
			}

			if (lease && requested_nip == lease->lease_nip) {
				debug(dhcp_server, "Sending ACK");
				send_ACK(dhcp_server, &packet,
						lease->lease_nip);
				break;
			}

			if (server_id_option || lease == NULL) {
				debug(dhcp_server, "Sending NAK");
				send_NAK(dhcp_server, &packet);
			}

		break;
		case DHCPDECLINE:
			debug(dhcp_server, "Received DECLINE");

			if (server_id_option == NULL)
				break;

			if (request_ip_option == NULL)
				break;

			if (lease == NULL)
				break;

			if (requested_nip == lease->lease_nip)
				remove_lease(dhcp_server, lease);

		break;
		case DHCPRELEASE:
			debug(dhcp_server, "Received RELEASE");

			if (server_id_option == NULL)
				break;

			if (lease == NULL)
				break;

			if (packet.ciaddr == lease->lease_nip)
				lease_set_expire(dhcp_server, lease,
								time(NULL));
		break;
		case DHCPINFORM:
			debug(dhcp_server, "Received INFORM");
			send_inform(dhcp_server, &packet);
		break;
	}

	return TRUE;
}
Пример #9
0
void process_dhcp(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset;
	struct DHCP dhcp;

	memset(&dhcp, 0, sizeof(dhcp));
	if (length < 200) {
		FRAMERR(frame, "dhcp: frame too short\n");
		return;
	}

	dhcp.op = px[0];
	dhcp.hardware_type = px[1];
	dhcp.hardware_address_length = px[2];
	dhcp.hops = px[3];

	dhcp.transaction_id = ex32be(px+4);
	dhcp.seconds_elapsed = ex16be(px+8);
	dhcp.flags = ex16be(px+10);

	dhcp.ciaddr = ex32be(px+12);
	dhcp.yiaddr = ex32be(px+16);
	dhcp.siaddr = ex32be(px+20);
	dhcp.giaddr = ex32be(px+24);

	memcpy(dhcp.chaddr, px+28, 16);
	dhcp.chaddr[16] = '\0';

	memcpy(dhcp.sname, px+28+16, 64);
	dhcp.sname[64] = '\0';

	memcpy(dhcp.file, px+28+16+64, 128);
	dhcp.file[128] = '\0';

	offset = 28+16+64+128;

	if (offset+4 > length)
		return;

	if (memcmp(px+offset, "\x63\x82\x53\x63", 4) != 0)
		return;
	offset += 4;

	/* Process special options */
	dhcp.msg = dhcp_number(px, length, 53);
	switch (dhcp.msg) {
	case 8: /* inform */
		/* Process vendor specific information */
		{
			const unsigned char *spec;
			unsigned spec_length;
			const unsigned char *id;
			unsigned id_length;

			dhcp_get_option(px, length, 43, &spec, &spec_length);
			dhcp_get_option(px, length, 60, &id, &id_length);

			if (spec_length && id_length) {
				process_record(seap,
					"application",	REC_PRINTABLE, id, id_length,
					"info",			REC_PRINTABLE, spec, spec_length,
					0);
			}
		}
	}



	process_dhcp_options(seap, frame, px, length, offset, &dhcp);

	if (dhcp.overload_filename)
		process_dhcp_options(seap, frame, px, 28+16+64+128, 28+16+64, &dhcp);
	if (dhcp.overload_servername)
		process_dhcp_options(seap, frame, px, 28+16+64, 28+16, &dhcp);

	SAMPLE("BOOTP", "type",	REC_UNSIGNED, &dhcp.op,	sizeof(dhcp.op));
	switch (dhcp.op) {
	case 1: /*BOOTP request */
		break;
	case 2: /*BOOTP reply*/ 
		switch (dhcp.msg) {
		case 2:
			break;
		case 5: /*ack*/
			break;
		case 6: /*DHCP NACK*/
			{
				const unsigned char *dst_mac;
				unsigned src_ip;

				if (dhcp.hardware_address_length != 6) {
					FRAMERR(frame, "dhcp: expected hardware address length = 6, found length = %d\n", dhcp.hardware_address_length);
					break;
				}
				if (memcmp(dhcp.chaddr, "\0\0\0\0\0\0", 6) == 0) {
					FRAMERR(frame, "dhcp: expected hardware address, but found [00:00:00:00:00:00]\n");
					break;
				} else
					dst_mac = &dhcp.chaddr[0];

				if (dhcp.server_identifier)
					src_ip = dhcp.server_identifier;
				else if (dhcp.siaddr)
					src_ip = dhcp.siaddr;
				else
					src_ip = frame->src_ipv4;

				process_record(seap,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"NACK",		-1,
					"src.ip",	REC_IPv4,		&src_ip,	sizeof(src_ip),
					"dst.mac",	REC_MACADDR,	dst_mac,	6,
					0);
			}
			break;
		case 8:
			break;
		default:
			FRAMERR(frame, "dhcp: unknown dhcp msg type %d\n", dhcp.msg);
			break;
		}
		break;
	default:
			FRAMERR(frame, "dhcp: unknown bootp op code %d\n", dhcp.op);
		break;

	}

}