Exemple #1
0
static int
ni_do_duid_create(int argc, char **argv)
{
	enum {	OPT_HELP = 'h' };
	static struct option    options[] = {
		{ "help",	no_argument,		NULL,	OPT_HELP	},
		{ NULL,		no_argument,		NULL,	0		}
	};
	int opt = 0, status = NI_WICKED_RC_USAGE;
	const char *type = NULL;
	char *command = NULL;

	optind = 1;
	while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) {
		switch (opt) {
		case OPT_HELP:
			status = NI_WICKED_RC_SUCCESS;
		default:
		usage:
			fprintf(stderr,
				"Usage: %s [options] <ll|llt|en|uuid> ...\n"
				"\n"
				"Options:\n"
				"  --help, -h           show this help text and exit.\n"
				"\n", argv[0]);
			goto cleanup;
		}
	}
	if (optind >= argc || ni_string_empty(argv[optind])) {
		fprintf(stderr, "%s: missing duid type argument\n\n", argv[0]);
		goto usage;
	}

	type = argv[optind];
	ni_string_printf(&command, "%s %s", argv[0], type);
	argv[optind] = command;

	if (ni_string_eq(type, "ll")) {
		status = ni_do_duid_create_ll(argc - optind, argv + optind);
	} else
	if (ni_string_eq(type, "llt")) {
		status = ni_do_duid_create_llt(argc - optind, argv + optind);
	} else
	if (ni_string_eq(type, "en")) {
		status = ni_do_duid_create_en(argc - optind, argv + optind);
	} else
	if (ni_string_eq(type, "uuid")) {
		status = ni_do_duid_create_uuid(argc - optind, argv + optind);
	} else {
		argv[optind] = (char *)type;
		fprintf(stderr, "%s: unsupported duid type '%s'\n", argv[0],
				ni_print_suspect(type, ni_string_len(type)));
		goto usage;
	}
	argv[optind] = (char *)type;

cleanup:
	ni_string_free(&command);
	return status;
}
Exemple #2
0
static int
ni_do_duid_del(int argc, char **argv)
{
	enum {	OPT_HELP = 'h', OPT_SCOPE = 's' };
	static struct option    options[] = {
		{ "help",	no_argument,		NULL,	OPT_HELP	},
		{ "scope",	required_argument,	NULL,	OPT_SCOPE	},
		{ NULL,		no_argument,		NULL,	0		}
	};
	int opt = 0, status = NI_WICKED_RC_USAGE;
	ni_duid_map_t *map = NULL;
	const char *scope = NULL;

	optind = 1;
	while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) {
		switch (opt) {
		case OPT_SCOPE:
			if (optarg && !ni_string_eq(optarg, "default"))
				scope = optarg;
			break;
		case OPT_HELP:
			status = NI_WICKED_RC_SUCCESS;
		default:
		usage:
			fprintf(stderr,
				"Usage: %s [options]\n"
				"\n"
				"Options:\n"
				"  --help, -h           show this help text and exit.\n"
				"  --scope <ifname>     delete device specific duid instead of default\n"
				"\n", argv[0]);
			goto cleanup;
		}
	}
	if (argc - optind)
		goto usage;

	if (scope && !ni_netdev_name_is_valid(scope)) {
		fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0],
				ni_print_suspect(scope, ni_string_len(scope)));
		status = NI_WICKED_RC_ERROR;
		goto cleanup;
	}

	status = NI_WICKED_RC_ERROR;
	if (!(map = ni_duid_map_load(NULL)))
		goto cleanup;

	if (ni_duid_map_del(map, scope)) {
		if (ni_duid_map_save(map))
			status = NI_WICKED_RC_SUCCESS;
	}

cleanup:
	ni_duid_map_free(map);
	return status;
}
Exemple #3
0
static int
ni_dhcp4_option_get_domain_list(ni_buffer_t *bp, ni_string_array_t *var,
					const char *what)
{
	ni_string_array_t list = NI_STRING_ARRAY_INIT;
	unsigned int len, i;
	char *tmp = NULL;

	if (ni_dhcp4_option_get_string(bp, &tmp, &len) < 0)
		return -1;

	/*
	 * Hack to accept "compatibility abuse" of dns domain name
	 * option containing multiple domains instead to send them
	 * using a dns-search option...
	 */
	if (!ni_string_split(&list, tmp, " ", 0)) {
		ni_warn("Discarded suspect %s: '%s'", what,
				ni_print_suspect(tmp, len));
		free(tmp);
		return -1;
	}
	for (i = 0; i < list.count; ++i) {
		const char *dom = list.data[i];
		if (!ni_check_domain_name(dom, ni_string_len(dom), 0)) {
			ni_warn("Discarded suspect %s: '%s'", what,
				ni_print_suspect(tmp, len));
			ni_string_array_destroy(&list);
			free(tmp);
			return -1;
		}
	}
	if (list.count != 1) {
		ni_warn("Abuse of %s option to provide a list: '%s'",
			what, tmp);
	}
	free(tmp);
	ni_string_array_move(var, &list);
	return 0;
}
Exemple #4
0
static int
ni_dhcp_option_get_printable(ni_buffer_t *bp, char **var, const char *what)
{
	unsigned int len;
	char *tmp = NULL;

	if (ni_dhcp_option_get_string(bp, &tmp, &len) < 0)
		return -1;

	if (!ni_check_printable(tmp, len)) {
		ni_debug_dhcp("Discarded non-printable %s: %s", what,
			ni_print_suspect(tmp, len));
		free(tmp);
		return -1;
	}

	if (*var)
		free(*var);
	*var = tmp;
	return 0;
}
Exemple #5
0
static int
ni_dhcp4_option_get_pathname(ni_buffer_t *bp, char **var, const char *what)
{
	unsigned int len;
	char *tmp = NULL;

	if (ni_dhcp4_option_get_string(bp, &tmp, &len) < 0)
		return -1;

	if (!ni_check_pathname(tmp, len)) {
		ni_warn("Discarded suspect %s: '%s'", what,
			ni_print_suspect(tmp, len));
		free(tmp);
		return -1;
	}

	if (*var)
		free(*var);
	*var = tmp;
	return 0;
}
Exemple #6
0
static int
__ni_rtevent_process_dnssl_info(ni_netdev_t *dev, const struct nd_opt_hdr *opt, size_t len)
{
	const struct ni_nd_opt_dnssl_info_p *dopt;
	ni_ipv6_devinfo_t *ipv6;
	unsigned int lifetime;
	struct timeval acquired;
	size_t length, cnt, off;
	ni_bool_t emit = FALSE;
	char domain[256];

	if (opt == NULL || len < sizeof(*dopt)) {
		ni_error("%s: unable to parse ipv6 dnssl info event data -- too short",
				dev->name);
		return -1;
	}

	ipv6 = ni_netdev_get_ipv6(dev);
	if (!ipv6) {
		ni_error("%s: unable to allocate device ipv6 structure: %m",
				dev->name);
		return -1;
	}

	dopt = (const struct ni_nd_opt_dnssl_info_p *)opt;
	len -= sizeof(*dopt);

	ni_timer_get_time(&acquired);
	lifetime = ntohl(dopt->nd_opt_dnssl_lifetime);

	length = 0;
	domain[length] = '\0';
	for (off = 0; off < len ; ) {
		cnt = dopt->nd_opt_dnssl_list[off++];
		if (cnt == 0) {
			/* just padding */
			if (domain[0] == '\0')
				continue;

			domain[length] = '\0';
			if (!ni_check_domain_name(domain, length, 0)) {
				ni_debug_verbose(NI_LOG_DEBUG, NI_TRACE_IPV6|NI_TRACE_EVENTS,
					"%s: ignoring suspect DNSSL domain: %s",
					dev->name, ni_print_suspect(domain, length));
			} else
			if (!ni_ipv6_ra_dnssl_list_update(&ipv6->radv.dnssl,
						domain, lifetime, &acquired)) {
				ni_debug_verbose(NI_LOG_DEBUG, NI_TRACE_IPV6|NI_TRACE_EVENTS,
						"%s: unable to track ipv6 dnssl domain %s",
						dev->name, domain);
			} else
				emit = TRUE;

			length = 0;
			domain[length] = '\0';
			continue;
		}

		if ((off + cnt >= len) || (length + cnt + 2 > sizeof(domain)))
			break;

		if (length)
			domain[length++] = '.';
		memcpy(&domain[length], &dopt->nd_opt_dnssl_list[off], cnt);
		off += cnt;
		length += cnt;
		domain[length] = '\0';
	}

	if (emit)
		__ni_netdev_nduseropt_event(dev, NI_EVENT_DNSSL_UPDATE);
	return 0;
}
Exemple #7
0
/*
 * Process a request to reconfigure the device (ie rebind a lease, or discover
 * a new lease).
 */
int
ni_dhcp4_acquire(ni_dhcp4_device_t *dev, const ni_dhcp4_request_t *info)
{
	ni_dhcp4_config_t *config;
	const char *classid;
	size_t len;
	int rv;

	if ((rv = ni_dhcp4_device_refresh(dev)) < 0)
		return rv;

	config = xcalloc(1, sizeof(*config));
	config->dry_run = info->dry_run;
	config->resend_timeout = NI_DHCP4_RESEND_TIMEOUT_INIT;
	config->request_timeout = info->acquire_timeout?: NI_DHCP4_REQUEST_TIMEOUT;
	config->initial_discovery_timeout = NI_DHCP4_DISCOVERY_TIMEOUT;
	config->uuid = info->uuid;
	config->flags = info->flags;
	config->update = info->update;
	config->route_priority = info->route_priority;
	config->start_delay = info->start_delay;
	config->recover_lease = info->recover_lease;
	config->release_lease = info->release_lease;

	config->max_lease_time = ni_dhcp4_config_max_lease_time();
	if (config->max_lease_time == 0)
		config->max_lease_time = ~0U;
	if (info->lease_time && info->lease_time < config->max_lease_time)
		config->max_lease_time = info->lease_time;

	if ((len = ni_string_len(info->hostname)) > 0) {
		if (ni_check_domain_name(info->hostname, len, 0)) {
			strncpy(config->hostname, info->hostname, sizeof(config->hostname) - 1);
		} else {
			ni_debug_dhcp("Discarded request to use suspect hostname: '%s'",
				ni_print_suspect(info->hostname, len));
		}
	}

	if (info->clientid) {
		ni_dhcp4_parse_client_id(&config->client_id, dev->system.hwaddr.type,
					 info->clientid);
	} else {
		/* Set client ID from interface hwaddr */
		ni_dhcp4_set_client_id(&config->client_id, &dev->system.hwaddr);
	}

	if ((classid = info->vendor_class) == NULL)
		classid = ni_dhcp4_config_vendor_class();
	if (classid)
		strncpy(config->classid, classid, sizeof(config->classid) - 1);

	config->doflags = DHCP4_DO_DEFAULT;
	config->doflags |= ni_dhcp4_do_bits(info->update);

	if (ni_debug & NI_TRACE_DHCP) {
		ni_trace("Received request:");
		ni_trace("  acquire-timeout %u", config->request_timeout);
		ni_trace("  lease-time      %u", config->max_lease_time);
		ni_trace("  start-delay     %u", config->start_delay);
		ni_trace("  hostname        %s", config->hostname[0]? config->hostname : "<none>");
		ni_trace("  vendor-class    %s", config->classid[0]? config->classid : "<none>");
		ni_trace("  client-id       %s", ni_print_hex(config->client_id.data, config->client_id.len));
		ni_trace("  uuid            %s", ni_uuid_print(&config->uuid));
		ni_trace("  update-flags    %s", __ni_dhcp4_print_doflags(config->doflags));
		ni_trace("  recover_lease   %s", config->recover_lease ? "true" : "false");
		ni_trace("  release_lease   %s", config->release_lease ? "true" : "false");
	}

	ni_dhcp4_device_set_config(dev, config);

	if (!dev->lease)
		ni_dhcp4_recover_lease(dev);

	if (dev->lease) {
		if (!ni_addrconf_lease_is_valid(dev->lease)
		 || (config->client_id.len && !ni_opaque_eq(&config->client_id, &dev->lease->dhcp4.client_id))) {
			ni_debug_dhcp("%s: lease doesn't match request", dev->ifname);
			ni_dhcp4_device_drop_lease(dev);
			dev->notify = 1;
		}
	}

	ni_note("%s: Request to acquire DHCPv4 lease with UUID %s",
		dev->ifname, ni_uuid_print(&config->uuid));

	if (ni_dhcp4_device_start(dev) < 0)
		return -1;
	return 1;
}
Exemple #8
0
/*
 * Parse a DHCP response.
 * FIXME: RFC2131 states that the server is allowed to split a DHCP option into
 * several (partial) options if the total length exceeds 255 octets. We don't
 * handle this yet.
 */
int
ni_dhcp_parse_response(const ni_dhcp_message_t *message, ni_buffer_t *options, ni_addrconf_lease_t **leasep)
{
	ni_buffer_t overload_buf;
	ni_addrconf_lease_t *lease;
	ni_route_array_t default_routes = NI_ROUTE_ARRAY_INIT;
	ni_route_array_t static_routes = NI_ROUTE_ARRAY_INIT;
	ni_route_array_t classless_routes = NI_ROUTE_ARRAY_INIT;
	ni_string_array_t dns_servers = NI_STRING_ARRAY_INIT;
	ni_string_array_t dns_search = NI_STRING_ARRAY_INIT;
	ni_string_array_t nis_servers = NI_STRING_ARRAY_INIT;
	char *nisdomain = NULL;
	char *dnsdomain = NULL;
	int opt_overload = 0;
	int msg_type = -1;
	int use_bootserver = 1;
	int use_bootfile = 1;

	lease = ni_addrconf_lease_new(NI_ADDRCONF_DHCP, AF_INET);

	lease->state = NI_ADDRCONF_STATE_GRANTED;
	lease->type = NI_ADDRCONF_DHCP;
	lease->family = AF_INET;
	lease->time_acquired = time(NULL);

	lease->dhcp.address.s_addr = message->yiaddr;
	lease->dhcp.serveraddress.s_addr = message->siaddr;
	lease->dhcp.address.s_addr = message->yiaddr;

parse_more:
	/* Loop as long as we still have data in the buffer. */
	while (ni_buffer_count(options) && !options->underflow) {
		ni_buffer_t buf;
		int option;

		option = ni_dhcp_option_next(options, &buf);

		//ni_debug_dhcp("handle option %s (%d)", ni_dhcp_option_name(option), option);
		if (option == DHCP_PAD)
			continue;

		if (option == DHCP_END)
			break;

		if (option < 0)
			goto error;

		if (ni_buffer_count(&buf) == 0) {
			ni_error("option %d has zero length", option);
			goto error;
		}

		switch (option) {
		case DHCP_MESSAGETYPE:
			msg_type = ni_buffer_getc(&buf);
			if (msg_type < 0)
				goto error;
			continue;
		case DHCP_ADDRESS:
			ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.address);
			break;
		case DHCP_NETMASK:
			ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.netmask);
			break;
		case DHCP_BROADCAST:
			ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.broadcast);
			break;
		case DHCP_SERVERIDENTIFIER:
			ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.serveraddress);
			break;
		case DHCP_LEASETIME:
			ni_dhcp_option_get32(&buf, &lease->dhcp.lease_time);
			break;
		case DHCP_RENEWALTIME:
			ni_dhcp_option_get32(&buf, &lease->dhcp.renewal_time);
			break;
		case DHCP_REBINDTIME:
			ni_dhcp_option_get32(&buf, &lease->dhcp.rebind_time);
			break;
		case DHCP_MTU:
			ni_dhcp_option_get16(&buf, &lease->dhcp.mtu);
			/* Minimum legal mtu is 68 accoridng to
			 * RFC 2132. In practise it's 576 which is the
			 * minimum maximum message size. */
			if (lease->dhcp.mtu < MTU_MIN) {
				ni_debug_dhcp("MTU %u is too low, minimum is %d; ignoring",
						lease->dhcp.mtu, MTU_MIN);
				lease->dhcp.mtu = 0;
			}
			break;
		case DHCP_HOSTNAME:
			ni_dhcp_option_get_domain(&buf, &lease->hostname,
							"hostname");
			break;
		case DHCP_DNSDOMAIN:
			ni_dhcp_option_get_domain(&buf, &dnsdomain,
							"dns-domain");
			break;
		case DHCP_MESSAGE:
			ni_dhcp_option_get_printable(&buf, &lease->dhcp.message,
							"dhcp-message");
			break;
		case DHCP_ROOTPATH:
			ni_dhcp_option_get_pathname(&buf, &lease->dhcp.rootpath,
							"root-path");
			break;
		case DHCP_NISDOMAIN:
			ni_dhcp_option_get_domain(&buf, &nisdomain,
							"nis-domain");
			break;
		case DHCP_NETBIOSNODETYPE:
			ni_dhcp_option_get_netbios_type(&buf, &lease->netbios_type);
			break;
		case DHCP_NETBIOSSCOPE:
			ni_dhcp_option_get_domain(&buf, &lease->netbios_scope,
							"netbios-scope");
			break;
		case DHCP_DNSSERVER:
			ni_dhcp_decode_address_list(&buf, &dns_servers);
			break;
		case DHCP_NTPSERVER:
			ni_dhcp_decode_address_list(&buf, &lease->ntp_servers);
			break;
		case DHCP_NISSERVER:
			ni_dhcp_decode_address_list(&buf, &nis_servers);
			break;
		case DHCP_LPRSERVER:
			ni_dhcp_decode_address_list(&buf, &lease->lpr_servers);
			break;
		case DHCP_LOGSERVER:
			ni_dhcp_decode_address_list(&buf, &lease->log_servers);
			break;
		case DHCP_NETBIOSNAMESERVER:
			ni_dhcp_decode_address_list(&buf, &lease->netbios_name_servers);
			break;
		case DHCP_NETBIOSDDSERVER:
			ni_dhcp_decode_address_list(&buf, &lease->netbios_dd_servers);
			break;
		case DHCP_DNSSEARCH:
			ni_dhcp_decode_dnssearch(&buf, &dns_search, "dns-search domain");
			break;

		case DHCP_CSR:
		case DHCP_MSCSR:
			ni_route_array_destroy(&classless_routes);
			if (ni_dhcp_decode_csr(&buf, &classless_routes) < 0)
				goto error;
			break;

		case DHCP_SIPSERVER:
			ni_dhcp_decode_sipservers(&buf, &lease->sip_servers);
			break;

		case DHCP_STATICROUTE:
			ni_route_array_destroy(&static_routes);
			if (ni_dhcp_decode_static_routes(&buf, &static_routes) < 0)
				goto error;
			break;

		case DHCP_ROUTERS:
			ni_route_array_destroy(&default_routes);
			if (ni_dhcp_decode_routers(&buf, &default_routes) < 0)
				goto error;
			break;

		case DHCP_OPTIONSOVERLOADED:
			if (options != &overload_buf) {
				opt_overload = ni_buffer_getc(&buf);
			} else {
				ni_debug_dhcp("DHCP: ignoring OVERLOAD option in overloaded data");
				(void) ni_buffer_getc(&buf);
			}
			break;

		case DHCP_FQDN:
			/* We ignore replies about FQDN */
			break;

		default:
			ni_debug_dhcp("ignoring unsupported DHCP code %u", option);
			break;
		}

		if (buf.underflow) {
			ni_debug_dhcp("unable to parse DHCP option %s: too short",
					ni_dhcp_option_name(option));
			goto error;
		} else if (ni_buffer_count(&buf)) {
			ni_debug_dhcp("excess data in DHCP option %s - %u bytes left",
					ni_dhcp_option_name(option),
					ni_buffer_count(&buf));
		}

	}

	if (options->underflow) {
		ni_debug_dhcp("unable to parse DHCP response: truncated packet");
		goto error;
	}

	if (opt_overload) {
		const void *more_data = NULL;
		size_t size = 0;

		if (opt_overload & DHCP_OVERLOAD_BOOTFILE) {
			use_bootfile = 0;
			more_data = message->bootfile;
			size = sizeof(message->bootfile);
			opt_overload &= ~DHCP_OVERLOAD_BOOTFILE;
		} else
		if (opt_overload & DHCP_OVERLOAD_SERVERNAME) {
			use_bootserver = 0;
			more_data = message->servername;
			size = sizeof(message->servername);
			opt_overload &= ~DHCP_OVERLOAD_SERVERNAME;
		} else {
			opt_overload = 0;
		}
		if (more_data) {
			ni_buffer_init_reader(&overload_buf, (void *) more_data, size);
			options = &overload_buf;
			goto parse_more;
		}
	}

	if (use_bootserver && message->servername[0]) {
		char tmp[sizeof(message->servername)];
		size_t len;

		assert(sizeof(lease->dhcp.servername) == sizeof(message->servername));
		memcpy(tmp, message->servername, sizeof(tmp));
		tmp[sizeof(tmp)-1] = '\0';

		len = ni_string_len(tmp);
		if (ni_check_domain_name(tmp, len, 0)) {
			memcpy(lease->dhcp.servername, tmp, sizeof(lease->dhcp.servername));
		} else {
			ni_debug_dhcp("Discarded suspect boot-server name: %s",
					ni_print_suspect(tmp, len));
		}
	}
	if (use_bootfile && message->bootfile[0]) {
		char tmp[sizeof(message->bootfile)];
		size_t len;

		memcpy(tmp, message->bootfile, sizeof(tmp));
		tmp[sizeof(tmp)-1] = '\0';
		len = ni_string_len(tmp);
		if (ni_check_pathname(tmp, len)) {
			ni_string_dup(&lease->dhcp.bootfile, tmp);
		} else {
			ni_debug_dhcp("Discarded suspect boot-file name: %s",
					ni_print_suspect(tmp, len));
		}
	}

	/* Fill in any missing fields */
	if (!lease->dhcp.netmask.s_addr) {
		unsigned int pfxlen = guess_prefix_len(lease->dhcp.address);

		lease->dhcp.netmask.s_addr = htonl(~(0xFFFFFFFF >> pfxlen));
	}
Exemple #9
0
/*
 * Decode an RFC3397 DNS search order option.
 */
static int
ni_dhcp_decode_dnssearch(ni_buffer_t *optbuf, ni_string_array_t *list, const char *what)
{
	ni_stringbuf_t namebuf = NI_STRINGBUF_INIT_DYNAMIC;
	unsigned char *base = ni_buffer_head(optbuf);
	unsigned int base_offset = optbuf->head;
	size_t len;

	ni_string_array_destroy(list);

	while (ni_buffer_count(optbuf) && !optbuf->underflow) {
		ni_buffer_t *bp = optbuf;
		ni_buffer_t jumpbuf;

		while (1) {
			unsigned int pos = bp->head - base_offset;
			unsigned int pointer;
			char label[64];
			int length;

			if ((length = ni_buffer_getc(bp)) < 0)
				goto failure; /* unexpected EOF */

			if (length == 0)
				break;	/* end of this name */

			switch (length & 0xC0) {
			case 0:
				/* Plain name component */
				if (ni_buffer_get(bp, label, length) < 0)
					goto failure;

				label[length] = '\0';
				if (!ni_stringbuf_empty(&namebuf))
					ni_stringbuf_putc(&namebuf, '.');
				ni_stringbuf_puts(&namebuf, label);
				break;

			case 0xC0:
				/* Pointer */
				pointer = (length & 0x3F) << 8;
				if ((length = ni_buffer_getc(bp)) < 0)
					goto failure;

				pointer |= length;
				if (pointer >= pos)
					goto failure;

				ni_buffer_init_reader(&jumpbuf, base, pos);
				jumpbuf.head = pointer;
				bp = &jumpbuf;
				break;

			default:
				goto failure;
			}

		}

		if (!ni_stringbuf_empty(&namebuf)) {

			len = ni_string_len(namebuf.string);
			if (ni_check_domain_name(namebuf.string, len, 0)) {
				ni_string_array_append(list, namebuf.string);
			} else {
				ni_debug_dhcp("Discarded suspect %s: %s", what,
					ni_print_suspect(namebuf.string, len));
			}
		}
		ni_stringbuf_destroy(&namebuf);
	}

	return 0;

failure:
	ni_stringbuf_destroy(&namebuf);
	ni_string_array_destroy(list);
	return -1;
}
Exemple #10
0
static int
ni_do_duid_create_uuid(int argc, char **argv)
{
	enum {	OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u',
		OPT_MACHINE_ID = 'm', OPT_PRODUCT_ID = 'p' };
	static struct option    options[] = {
		{ "help",	no_argument,		NULL,	OPT_HELP	},
		{ "scope",	required_argument,	NULL,	OPT_SCOPE	},
		{ "update",	no_argument,		NULL,	OPT_UPDATE	},
		{ "machine-id",	optional_argument,	NULL,	OPT_MACHINE_ID	},
		{ "product-id",	optional_argument,	NULL,	OPT_PRODUCT_ID	},
		{ NULL,		no_argument,		NULL,	0		}
	};
	int opt = 0, status = NI_WICKED_RC_USAGE;
	const char *scope = NULL;
	ni_bool_t update = FALSE;
	unsigned int type = 0;
	const char *from = NULL;
	const char *hex = NULL;
	ni_opaque_t raw;

	optind = 1;
	while ((opt = getopt_long(argc, argv, "+hs:um::p::", options, NULL)) != EOF) {
		switch (opt) {
		case OPT_MACHINE_ID:
			type = OPT_MACHINE_ID;
			from = optarg;
			break;
		case OPT_PRODUCT_ID:
			type = OPT_PRODUCT_ID;
			from = optarg;
			break;
		case OPT_UPDATE:
			update = TRUE;
			break;
		case OPT_SCOPE:
			if (optarg && !ni_string_eq(optarg, "default"))
				scope = optarg;
			break;
		case OPT_HELP:
			status = NI_WICKED_RC_SUCCESS;
		default:
		usage:
			fprintf(stderr,
				"Usage: %s [options] [uuid]\n"
				"\n"
				"Options:\n"
				"  --help, -h           show this help text and exit.\n"
				"  --scope <ifname>     create device specific duid instead of default\n"
				"  --update             create a duid and update duid map file\n"
				"  --machine-id[=FILE]  import uuid from /etc/machine-id file\n"
				"  --product-id[=FILE]  import uuid from dmi product-id sysfs file\n"
				"\n"
				"Arguments:\n"
				"  uuid                 create duid using specified uuid-string\n"
				"\n", argv[0]);
			goto cleanup;
		}
	}
	switch (type) {
	case OPT_MACHINE_ID:
	case OPT_PRODUCT_ID:
		if ((argc - optind) != 0)
			goto usage;
		break;
	default:
		if ((argc - optind) != 1)
			goto usage;
		from = argv[optind++];
		break;
	}

	status = NI_WICKED_RC_ERROR;
	if (scope && !ni_netdev_name_is_valid(scope)) {
		fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0],
				ni_print_suspect(scope, ni_string_len(scope)));
		goto cleanup;
	}

	switch (type) {
	case OPT_MACHINE_ID:
		if (!ni_duid_create_uuid_machine_id(&raw, from)) {
			fprintf(stderr, "%s: cannot create duid by importing uuid from machine-id%s%s",
					argv[0], from ? " file ": "", from ? from : "");
			goto cleanup;
		}
		break;
	case OPT_PRODUCT_ID:
		if (!ni_duid_create_uuid_dmi_product_id(&raw, from)) {
			fprintf(stderr, "%s: cannot create duid by importing uuid from dmi product-id%s%s",
					argv[0], from ? " file ": "", from ? from : "");
			goto cleanup;
		}
		break;
	default:
		if (!ni_duid_create_uuid_string(&raw, from)) {
			fprintf(stderr, "%s: cannot create duid by importing uuid string '%s'",
					argv[0], from);
			goto cleanup;
		}
		break;
	}

	hex = raw.len ? ni_duid_print_hex(&raw) : NULL;
	if (ni_string_empty(hex)) {
		fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]);
		goto cleanup;
	}

	if (update) {
		status = ni_do_duid_create_update(scope, hex);
		if (status != NI_WICKED_RC_SUCCESS) {
			fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]);
			goto cleanup;
		}
	}

	printf("%s\t%s\n", scope ? scope : "default", hex);
	status = NI_WICKED_RC_SUCCESS;

cleanup:
	return status;
}
Exemple #11
0
static int
ni_do_duid_create_ll_type(uint16_t type, int argc, char **argv)
{
	enum {	OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' };
	static struct option    options[] = {
		{ "help",	no_argument,		NULL,	OPT_HELP	},
		{ "scope",	required_argument,	NULL,	OPT_SCOPE	},
		{ "update",	no_argument,		NULL,	OPT_UPDATE	},
		{ NULL,		no_argument,		NULL,	0		}
	};
	int opt = 0, status = NI_WICKED_RC_USAGE;
	const char *scope = NULL;
	ni_bool_t update = FALSE;
	const char *ifname = NULL;
	const char *hwtype = NULL;
	const char *hwaddr = NULL;
	const char *hex = NULL;
	ni_opaque_t raw;

	optind = 1;
	while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) {
		switch (opt) {
		case OPT_UPDATE:
			update = TRUE;
			break;
		case OPT_SCOPE:
			if (optarg && !ni_string_eq(optarg, "default"))
				scope = optarg;
			break;
		case OPT_HELP:
			status = NI_WICKED_RC_SUCCESS;
		default:
		usage:
			fprintf(stderr,
				"Usage: %s [options] [ [ifname] | <hwtype> <hwaddr> ]\n"
				"\n"
				"Options:\n"
				"  --help, -h           show this help text and exit.\n"
				"  --scope <ifname>     create device specific duid instead of default\n"
				"  --update             create a duid and update duid map file\n"
				"\n"
				"Arguments:\n"
				"  ifname               get hardware type and address from interface\n"
				"  htwype               hardware type to use in the duid\n"
				"  htaddr               hardware address to use in the duid\n"
				"\n", argv[0]);
			ni_do_duid_create_ll_print_hwtypes(stderr);
			goto cleanup;
		}
	}
	switch (argc - optind) {
	case 2:
		hwtype = argv[optind++];
		hwaddr = argv[optind++];
		break;
	case 1:
		ifname = argv[optind++];
		break;
	case 0:
		break;
	default:
		goto usage;
	}

	status = NI_WICKED_RC_ERROR;
	if (scope && !ni_netdev_name_is_valid(scope)) {
		fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0],
				ni_print_suspect(scope, ni_string_len(scope)));
		goto cleanup;
	}

	if (hwtype || hwaddr) {
		switch (type) {
		case NI_DUID_TYPE_LL:
			if (ni_duid_create_ll(&raw, hwtype, hwaddr))
				status = NI_WICKED_RC_SUCCESS;
			break;
		case NI_DUID_TYPE_LLT:
			if (ni_duid_create_llt(&raw, hwtype, hwaddr))
				status = NI_WICKED_RC_SUCCESS;
			break;
		default:
			break;
		}
		if (status != NI_WICKED_RC_SUCCESS) {
			fprintf(stderr, "%s: cannot create duid using hardware type '%s' and address '%s'\n",
				argv[0], hwtype, hwaddr);
			goto cleanup;
		}
	} else {
		ni_netconfig_t *nc = ni_global_state_handle(1);
		ni_netdev_t *dev = NULL;

		if (!nc) {
			fprintf(stderr, "%s: cannot retrieve interface properties", argv[0]);
			goto cleanup;
		}

		if (ifname) {
			dev = ni_netdev_by_name(nc, ifname);
			if (!dev || !ni_duid_create_from_device(&raw, type, dev)) {
				hwtype = dev ? ni_duid_hwtype_to_name(dev->link.hwaddr.type) : "missing";
				fprintf(stderr, "%s: unable to create %s duid using %s device '%s'\n",
					argv[0], ni_duid_type_to_name(type),
					hwtype ? hwtype : "unsupported", ifname);
				goto cleanup;
			}
		} else {
			dev = scope ? ni_netdev_by_name(nc, scope) : NULL;
			if (!ni_duid_create_pref_device(&raw, type, nc, dev)) {
				fprintf(stderr, "%s: unable to create any %s duid (no usable devices)",
					argv[0], ni_duid_type_to_name(type));
				goto cleanup;
			}
		}
	}

	status = NI_WICKED_RC_ERROR;
	hex = raw.len ? ni_duid_print_hex(&raw) : NULL;
	if (ni_string_empty(hex)) {
		fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]);
		goto cleanup;
	}

	if (update) {
		status = ni_do_duid_create_update(scope, hex);
		if (status != NI_WICKED_RC_SUCCESS) {
			fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]);
			goto cleanup;
		}
	}

	printf("%s\t%s\n", scope ? scope : "default", hex);
	status = NI_WICKED_RC_SUCCESS;

cleanup:
	return status;
}
Exemple #12
0
static int
ni_do_duid_create_en(int argc, char **argv)
{
	enum {	OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' };
	static struct option    options[] = {
		{ "help",	no_argument,		NULL,	OPT_HELP	},
		{ "scope",	required_argument,	NULL,	OPT_SCOPE	},
		{ "update",	no_argument,		NULL,	OPT_UPDATE	},
		{ NULL,		no_argument,		NULL,	0		}
	};
	int opt = 0, status = NI_WICKED_RC_USAGE;
	const char *scope = NULL;
	ni_bool_t update = FALSE;
	const char *en = NULL;
	const char *id = NULL;
	const char *hex = NULL;
	ni_opaque_t raw;

	optind = 1;
	while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) {
		switch (opt) {
		case OPT_UPDATE:
			update = TRUE;
			break;
		case OPT_SCOPE:
			if (optarg && !ni_string_eq(optarg, "default"))
				scope = optarg;
			break;
		case OPT_HELP:
			status = NI_WICKED_RC_SUCCESS;
		default:
		usage:
			fprintf(stderr,
				"Usage: %s [options] <enterprise-number> <machine-identifier>\n"
				"\n"
				"Options:\n"
				"  --help, -h           show this help text and exit.\n"
				"  --scope <ifname>     create device specific duid instead of default\n"
				"  --update             create a duid and update duid map file\n"
				"\n"
				"Arguments:\n"
				"  enterprise-number    IANA assigned 32bit enterprise number\n"
				"  machine-identifier   machine identifier as colon-separated hex bytes\n"
				"\n", argv[0]);
			goto cleanup;
		}
	}
	switch (argc - optind) {
	case 2:
		en = argv[optind++];
		id = argv[optind++];
		break;
	default:
		goto usage;
	}

	status = NI_WICKED_RC_ERROR;
	if (scope && !ni_netdev_name_is_valid(scope)) {
		fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0],
				ni_print_suspect(scope, ni_string_len(scope)));
		goto cleanup;
	}

	if (!ni_duid_create_en(&raw, en, id)) {
		fprintf(stderr, "%s: cannot create duid using enterprise-number '%s' and identifier '%s'\n",
				argv[0], en, id);
		goto cleanup;
	}

	hex = raw.len ? ni_duid_print_hex(&raw) : NULL;
	if (ni_string_empty(hex)) {
		fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]);
		goto cleanup;
	}

	if (update) {
		status = ni_do_duid_create_update(scope, hex);
		if (status != NI_WICKED_RC_SUCCESS) {
			fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]);
			goto cleanup;
		}
	}

	printf("%s\t%s\n", scope ? scope : "default", hex);
	status = NI_WICKED_RC_SUCCESS;

cleanup:
	return status;
}
Exemple #13
0
static int
ni_do_duid_set(int argc, char **argv)
{
	enum { OPT_HELP = 'h', OPT_SCOPE = 's' };
	static struct option    options[] = {
		{ "help",	no_argument,		NULL,	OPT_HELP	},
		{ "scope",	required_argument,	NULL,	OPT_SCOPE	},
		{ NULL,		no_argument,		NULL,	0		}
	};
	int opt = 0, status = NI_WICKED_RC_USAGE;
	ni_duid_map_t *map = NULL;
	const char *scope = NULL;
	const char *duid = NULL;
	ni_opaque_t raw;

	optind = 1;
	while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) {
		switch (opt) {
		case OPT_SCOPE:
			if (optarg && !ni_string_eq(optarg, "default"))
				scope = optarg;
			break;
		case OPT_HELP:
			status = NI_WICKED_RC_SUCCESS;
		default:
		usage:
			fprintf(stderr,
				"Usage: %s [options] <duid>\n"
				"\n"
				"Options:\n"
				"  --help, -h           show this help text and exit.\n"
				"  --scope <ifname>     set device specific duid instead of default\n"
				"\n"
				"Arguments:\n"
				"  duid                 duid string as colon-separated hex bytes\n"
				"\n", argv[0]);
			goto cleanup;
		}
	}
	switch (argc - optind) {
	case 1:
		duid   = argv[optind++];
		break;
	default:
		goto usage;
	}

	if (scope && !ni_netdev_name_is_valid(scope)) {
		fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0],
				ni_print_suspect(scope, ni_string_len(scope)));
		status = NI_WICKED_RC_ERROR;
		goto cleanup;
	}
	if (ni_string_empty(duid) || !ni_duid_parse_hex(&raw, duid)) {
		fprintf(stderr, "%s: unable to parse duid hex string argument\n", argv[0]);
		status = NI_WICKED_RC_ERROR;
		goto cleanup;
	}

	status = NI_WICKED_RC_ERROR;
	if (!(map = ni_duid_map_load(NULL)))
		goto cleanup;

	if (!ni_duid_map_set(map, scope, duid))
		goto cleanup;

	if (!ni_duid_map_save(map))
		goto cleanup;

	status = NI_WICKED_RC_SUCCESS;

cleanup:
	ni_duid_map_free(map);
	return status;
}
Exemple #14
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;
}