예제 #1
0
파일: protocol.c 프로젝트: mchf/wicked
/*
 * Inline functions for setting/retrieving options from a buffer
 */
static inline void
ni_dhcp_option_put(ni_buffer_t *bp, int code, const void *data, size_t len)
{
	ni_buffer_putc(bp, code);
	ni_buffer_putc(bp, len);
	ni_buffer_put(bp, data, len);
}
예제 #2
0
파일: arp.c 프로젝트: gsanso/wicked
int
ni_arp_send(ni_arp_socket_t *arph, const ni_arp_packet_t *packet)
{
	unsigned int hwlen, pktlen;
	struct arphdr *arp;
	ni_buffer_t buf;
	int rv;

	hwlen = ni_link_address_length(arph->dev_info.hwaddr.type);
	pktlen = sizeof(*arp) + 2 * hwlen + 2 * 4;

	arp = calloc(1, pktlen);
	ni_buffer_init(&buf, arp, pktlen);

	arp = ni_buffer_push_tail(&buf, sizeof(*arp));
	arp->ar_hrd = htons(arph->dev_info.hwaddr.type);
	arp->ar_pro = htons(ETHERTYPE_IP);
	arp->ar_hln = hwlen;
	arp->ar_pln = 4;
	arp->ar_op = htons(packet->op);

	if (packet->sha.len == hwlen) {
		ni_buffer_put(&buf, packet->sha.data, packet->sha.len);
	} else {
		ni_buffer_put(&buf, NULL, hwlen);
	}
	ni_buffer_put(&buf, &packet->sip, 4);
	if (packet->tha.len == hwlen) {
		ni_buffer_put(&buf, packet->tha.data, packet->tha.len);
	} else {
		ni_buffer_put(&buf, NULL, hwlen);
	}
	ni_buffer_put(&buf, &packet->tip, 4);

	rv = ni_capture_send(arph->capture, &buf, NULL);
	free(buf.base);
	return rv;
}
예제 #3
0
파일: protocol.c 프로젝트: mchf/wicked
int
ni_dhcp_build_message(const ni_dhcp_device_t *dev,
			unsigned int msg_code,
			const ni_addrconf_lease_t *lease,
			ni_buffer_t *msgbuf)
{
	const ni_dhcp_config_t *options = dev->config;
	struct in_addr src_addr, dst_addr;
	ni_dhcp_message_t *message = NULL;

	if (!options || !lease)
		return -1;

	if (IN_LINKLOCAL(ntohl(lease->dhcp.address.s_addr))) {
		ni_error("cannot request a link local address");
		goto failed;
	}

	src_addr.s_addr = dst_addr.s_addr = 0;
	switch (msg_code) {
	case DHCP_DISCOVER:
		if (lease->dhcp.serveraddress.s_addr != 0)
			return -1;
		break;

	case DHCP_REQUEST:
	case DHCP_RELEASE:
	case DHCP_INFORM:
		if (lease->dhcp.address.s_addr == 0 || lease->dhcp.serveraddress.s_addr == 0)
			return -1;
		src_addr = lease->dhcp.address;
		dst_addr = lease->dhcp.serveraddress;
		break;
	}

	/* Reserve some room for the IP and UDP header */
	ni_buffer_reserve_head(msgbuf, sizeof(struct ip) + sizeof(struct udphdr));

	/* Build the message */
	message = ni_buffer_push_tail(msgbuf, sizeof(*message));

	message->op = DHCP_BOOTREQUEST;
	message->hwtype = dev->system.arp_type;
	message->xid = dev->dhcp.xid;
	message->cookie = htonl(MAGIC_COOKIE);
	message->secs = htons(ni_dhcp_device_uptime(dev, 0xFFFF));

	if (dev->fsm.state == NI_DHCP_STATE_BOUND
	 || dev->fsm.state == NI_DHCP_STATE_RENEWING
	 || dev->fsm.state == NI_DHCP_STATE_REBINDING)
		message->ciaddr = lease->dhcp.address.s_addr;

	switch (dev->system.arp_type) {
	case ARPHRD_ETHER:
	case ARPHRD_IEEE802:
		if (dev->system.hwaddr.len > sizeof(message->chaddr)) {
			ni_error("dhcp cannot handle hwaddress length %u",
					dev->system.hwaddr.len);
			goto failed;
		}
		message->hwlen = dev->system.hwaddr.len;
		memcpy(&message->chaddr, dev->system.hwaddr.data, dev->system.hwaddr.len);
		break;

	case ARPHRD_IEEE1394:
	case ARPHRD_INFINIBAND:
		message->hwlen = 0;
		if (message->ciaddr == 0)
			message->flags = htons(BROADCAST_FLAG);
		break;

	default:
		ni_error("dhcp: unknown hardware type %d", dev->system.arp_type);
	}

	ni_dhcp_option_put8(msgbuf, DHCP_MESSAGETYPE, msg_code);

	if (msg_code == DHCP_REQUEST)
		ni_dhcp_option_put16(msgbuf, DHCP_MAXMESSAGESIZE, dev->system.mtu);

	ni_dhcp_option_put(msgbuf, DHCP_CLIENTID,
			options->raw_client_id.data,
			options->raw_client_id.len);

	if (msg_code != DHCP_DECLINE && msg_code != DHCP_RELEASE) {
		if (options->userclass.len > 0)
			ni_dhcp_option_put(msgbuf, DHCP_USERCLASS,
					options->userclass.data,
					options->userclass.len);

		if (options->classid && options->classid[0])
			ni_dhcp_option_puts(msgbuf, DHCP_CLASSID, options->classid);
	}

	if (msg_code == DHCP_DISCOVER || msg_code == DHCP_REQUEST) {
		if (lease->dhcp.address.s_addr)
			ni_dhcp_option_put_ipv4(msgbuf, DHCP_ADDRESS, lease->dhcp.address);
		if (lease->dhcp.lease_time != 0)
			ni_dhcp_option_put32(msgbuf, DHCP_LEASETIME, lease->dhcp.lease_time);
	}

	if (msg_code == DHCP_REQUEST) {
		if (lease->dhcp.serveraddress.s_addr)
			ni_dhcp_option_put_ipv4(msgbuf, DHCP_SERVERIDENTIFIER, lease->dhcp.serveraddress);
	}

	if (msg_code == DHCP_DISCOVER || msg_code == DHCP_INFORM || msg_code == DHCP_REQUEST) {
		unsigned int params_begin;

		if (options->hostname && options->hostname[0]) {
			if (options->fqdn == FQDN_DISABLE) {
				ni_dhcp_option_puts(msgbuf, DHCP_HOSTNAME, options->hostname);
			} else {
				/* IETF DHC-FQDN option(81)
				 * http://tools.ietf.org/html/rfc4702#section-2.1
				 *
				 * Flags: 0000NEOS
				 * S: 1 => Client requests Server to update
				 *         a RR in DNS as well as PTR
				 * O: 1 => Server indicates to client that
				 *         DNS has been updated
				 * E: 1 => Name data is DNS format
				 * N: 1 => Client requests Server to not
				 *         update DNS
				 */
				ni_buffer_putc(msgbuf, DHCP_FQDN);
				ni_buffer_putc(msgbuf, strlen(options->hostname) + 3);
				ni_buffer_putc(msgbuf, options->fqdn & 0x9);
				ni_buffer_putc(msgbuf, 0);	/* from server for PTR RR */
				ni_buffer_putc(msgbuf, 0);	/* from server for A RR if S=1 */
				ni_buffer_put(msgbuf, options->hostname, strlen(options->hostname));
			}
		}

		params_begin = ni_dhcp_option_begin(msgbuf, DHCP_PARAMETERREQUESTLIST);

		if (msg_code == DHCP_DISCOVER) {
			/* dhcpcd says we should include just a single option
			 * in discovery packets.
			 * I'm not convinced this is right, but let's do it
			 * this way.
			 */
			ni_buffer_putc(msgbuf, DHCP_DNSSERVER);
		} else {
			if (msg_code != DHCP_INFORM) {
				ni_buffer_putc(msgbuf, DHCP_RENEWALTIME);
				ni_buffer_putc(msgbuf, DHCP_REBINDTIME);
			}
			ni_buffer_putc(msgbuf, DHCP_NETMASK);
			ni_buffer_putc(msgbuf, DHCP_BROADCAST);

			if (options->flags & DHCP_DO_CSR)
				ni_buffer_putc(msgbuf, DHCP_CSR);
			if (options->flags & DHCP_DO_MSCSR)
				ni_buffer_putc(msgbuf, DHCP_MSCSR);

			/* RFC 3442 states classless static routes should be
			 * before routers and static routes as classless static
			 * routes override them both */
			ni_buffer_putc(msgbuf, DHCP_STATICROUTE);
			ni_buffer_putc(msgbuf, DHCP_ROUTERS);
			ni_buffer_putc(msgbuf, DHCP_HOSTNAME);
			ni_buffer_putc(msgbuf, DHCP_DNSSEARCH);
			ni_buffer_putc(msgbuf, DHCP_DNSDOMAIN);
			ni_buffer_putc(msgbuf, DHCP_DNSSERVER);

			if (options->flags & DHCP_DO_NIS) {
				ni_buffer_putc(msgbuf, DHCP_NISDOMAIN);
				ni_buffer_putc(msgbuf, DHCP_NISSERVER);
			}
			if (options->flags & DHCP_DO_NTP)
				ni_buffer_putc(msgbuf, DHCP_NTPSERVER);
			ni_buffer_putc(msgbuf, DHCP_MTU);
			ni_buffer_putc(msgbuf, DHCP_ROOTPATH);
			ni_buffer_putc(msgbuf, DHCP_SIPSERVER);
			ni_buffer_putc(msgbuf, DHCP_LPRSERVER);
			ni_buffer_putc(msgbuf, DHCP_LOGSERVER);
			ni_buffer_putc(msgbuf, DHCP_NETBIOSNAMESERVER);
			ni_buffer_putc(msgbuf, DHCP_NETBIOSDDSERVER);
			ni_buffer_putc(msgbuf, DHCP_NETBIOSNODETYPE);
			ni_buffer_putc(msgbuf, DHCP_NETBIOSSCOPE);
		}

		ni_dhcp_option_end(msgbuf, params_begin);
	}
	ni_buffer_putc(msgbuf, DHCP_END);

#ifdef BOOTP_MESSAGE_LENGTH_MIN
	ni_buffer_pad(msgbuf, BOOTP_MESSAGE_LENGTH_MIN, DHCP_PAD);
#endif

	if (ni_capture_build_udp_header(msgbuf, src_addr, DHCP_CLIENT_PORT, dst_addr, DHCP_SERVER_PORT) < 0) {
		ni_error("unable to build packet header");
		goto failed;
	}

	return 0;

failed:
	return -1;
}
예제 #4
0
static int
__ni_dhcp4_build_msg_put_our_hostname(const ni_dhcp4_device_t *dev,
					ni_buffer_t *msgbuf)
{
	const ni_dhcp4_config_t *options = dev->config;
	size_t len = ni_string_len(options->hostname);

	if (!len)
		return 1; /* skipped hint */

	if (options->fqdn == FQDN_DISABLE) {
		char hname[64] = {'\0'}, *end;

		/*
		 * Truncate the domain part if fqdn to avoid attempts
		 * to update DNS with foo.bar + update-domain.
		 */
		strncat(hname, options->hostname, sizeof(hname)-1);
		if ((end = strchr(hname, '.')))
			*end = '\0';

		len = ni_string_len(hname);
		if (ni_check_domain_name(hname, len, 0)) {
			ni_dhcp4_option_puts(msgbuf, DHCP4_HOSTNAME, hname);
			ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP,
				"%s: using hostname: %s", dev->ifname, hname);
		} else {
			ni_info("%s: not sending suspect hostname: '%s'",
				dev->ifname, ni_print_suspect(hname, len));
			return 1;
		}
	} else
	if (ni_check_domain_name(options->hostname, len, 0)) {
		/* IETF DHC-FQDN option(81)
		 * http://tools.ietf.org/html/rfc4702#section-2.1
		 *
		 * Flags: 0000NEOS
		 * S: 1 => Client requests Server to update
		 *         a RR in DNS as well as PTR
		 * O: 1 => Server indicates to client that
		 *         DNS has been updated
		 * E: 1 => Name data is DNS format
		 * N: 1 => Client requests Server to not
		 *         update DNS
		 */
		ni_buffer_putc(msgbuf, DHCP4_FQDN);
		ni_buffer_putc(msgbuf, len + 3);
		ni_buffer_putc(msgbuf, options->fqdn & 0x9);
		ni_buffer_putc(msgbuf, 0);	/* from server for PTR RR */
		ni_buffer_putc(msgbuf, 0);	/* from server for A RR if S=1 */
		ni_buffer_put(msgbuf, options->hostname, len);
		ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP,
				"%s: using fqdn: %s", dev->ifname,
				options->hostname);
	} else {
		ni_info("%s: not sending suspect fqdn: '%s'",
			dev->ifname, ni_print_suspect(options->hostname, len));
		return 1;
	}

	return 0;
}