Example #1
0
/*
 * Set an error in a status-code option (from set_status_code).
 */
static int
set_error(struct lq6_state *lq, u_int16_t code, const char *message) {
	struct data_string d;
	int ret_val;

	memset(&d, 0, sizeof(d));
	d.len = sizeof(code) + strlen(message);
	if (!buffer_allocate(&d.buffer, d.len, MDL)) {
		log_fatal("set_error: no memory for status code.");
	}
	d.data = d.buffer->data;
	putUShort(d.buffer->data, code);
	memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code));
	if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts,
				d.buffer, (unsigned char *)d.data, d.len, 
				D6O_STATUS_CODE, 0)) {
		log_error("set_error: error saving status code.");
		ret_val = 0;
	} else {
		ret_val = 1;
	}
	data_string_forget(&d, MDL);
	return ret_val;
}
Example #2
0
void
convert_num(unsigned char *buf, char *str, int base, int size)
{
	int negative = 0, tval, max;
	u_int32_t val = 0;
	char *ptr = str;

	if (*ptr == '-') {
		negative = 1;
		ptr++;
	}

	/* If base wasn't specified, figure it out from the data. */
	if (!base) {
		if (ptr[0] == '0') {
			if (ptr[1] == 'x') {
				base = 16;
				ptr += 2;
			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
				base = 8;
				ptr += 1;
			} else
				base = 10;
		} else
			base = 10;
	}

	do {
		tval = *ptr++;
		/* XXX assumes ASCII... */
		if (tval >= 'a')
			tval = tval - 'a' + 10;
		else if (tval >= 'A')
			tval = tval - 'A' + 10;
		else if (tval >= '0')
			tval -= '0';
		else {
			warning("Bogus number: %s.", str);
			break;
		}
		if (tval >= base) {
			warning("Bogus number: %s: digit %d not in base %d",
			    str, tval, base);
			break;
		}
		val = val * base + tval;
	} while (*ptr);

	if (negative)
		max = (1 << (size - 1));
	else
		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
	if (val > max) {
		switch (base) {
		case 8:
			warning("value %s%o exceeds max (%d) for precision.",
			    negative ? "-" : "", val, max);
			break;
		case 16:
			warning("value %s%x exceeds max (%d) for precision.",
			    negative ? "-" : "", val, max);
			break;
		default:
			warning("value %s%u exceeds max (%d) for precision.",
			    negative ? "-" : "", val, max);
			break;
		}
	}

	if (negative)
		switch (size) {
		case 8:
			*buf = -(unsigned long)val;
			break;
		case 16:
			putShort(buf, -(unsigned long)val);
			break;
		case 32:
			putLong(buf, -(unsigned long)val);
			break;
		default:
			warning("Unexpected integer size: %d", size);
			break;
		}
	else
		switch (size) {
		case 8:
			*buf = (u_int8_t)val;
			break;
		case 16:
			putUShort(buf, (u_int16_t)val);
			break;
		case 32:
			putULong(buf, val);
			break;
		default:
			warning("Unexpected integer size: %d", size);
			break;
		}
}
Example #3
0
/*
 * Process a by-address lease query.
 */
static int
process_lq_by_address(struct lq6_state *lq) {
	struct packet *packet = lq->packet;
	struct option_cache *oc;
	struct ipv6_pool *pool = NULL;
	struct data_string data;
	struct in6_addr addr;
	struct iasubopt *iaaddr = NULL;
	struct option_state *opt_state = NULL;
	u_int32_t lifetime;
	unsigned opt_cursor;
	int ret_val = 0;

	/*
	 * Get the IAADDR.
	 */
	oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR);
	if (oc == NULL) {
		if (!set_error(lq, STATUS_MalformedQuery,
			       "No OPTION_IAADDR.")) {
			log_error("process_lq_by_address: unable "
				  "to set MalformedQuery status code.");
			return 0;
		}
		return 1;
	}
	memset(&data, 0, sizeof(data));
	if (!evaluate_option_cache(&data, packet,
				   NULL, NULL,
				   lq->query_opts, NULL,
				   &global_scope, oc, MDL) ||
	    (data.len < IAADDR_OFFSET)) {
		log_error("process_lq_by_address: error evaluating IAADDR.");
		goto exit;
	}
	memcpy(&addr, data.data, sizeof(addr));
	data_string_forget(&data, MDL);

	/*
	 * Find the lease.
	 * Note the RFC 5007 says to use the link-address to find the link
	 * or the ia-aadr when it is :: but in any case the ia-addr has
	 * to be on the link, so we ignore the link-address here.
	 */
	if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) {
		if (!set_error(lq, STATUS_NotConfigured,
			       "Address not in a pool.")) {
			log_error("process_lq_by_address: unable "
				  "to set NotConfigured status code.");
			goto exit;
		}
		ret_val = 1;
		goto exit;
	}
	if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr,
				 sizeof(addr), MDL) == 0) {
		ret_val = 1;
		goto exit;
	}
	if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) ||
	    (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) {
		ret_val = 1;
		goto exit;
	}

	/*
	 * Build the client-data option (with client-id, ia-addr and clt-time).
	 */
	if (!option_state_allocate(&opt_state, MDL)) {
		log_error("process_lq_by_address: "
			  "no memory for option state.");
		goto exit;
	}

	data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL);
	data.data += 4;
	data.len -= 4;
	if (!save_option_buffer(&dhcpv6_universe, opt_state,
				NULL, (unsigned char *)data.data, data.len,
				D6O_CLIENTID, 0)) {
		log_error("process_lq_by_address: error saving client ID.");
		goto exit;
	}
	data_string_forget(&data, MDL);

	data.len = IAADDR_OFFSET;
	if (!buffer_allocate(&data.buffer, data.len, MDL)) {
		log_error("process_lq_by_address: no memory for ia-addr.");
		goto exit;
	}
	data.data = data.buffer->data;
	memcpy(data.buffer->data, &iaaddr->addr, 16);
	lifetime = iaaddr->prefer;
	putULong(data.buffer->data + 16, lifetime);
	lifetime = iaaddr->valid;
	putULong(data.buffer->data + 20, lifetime);
	if (!save_option_buffer(&dhcpv6_universe, opt_state,
				NULL, (unsigned char *)data.data, data.len,
				D6O_IAADDR, 0)) {
		log_error("process_lq_by_address: error saving ia-addr.");
		goto exit;
	}
	data_string_forget(&data, MDL);

	lifetime = htonl(iaaddr->ia->cltt);
	if (!save_option_buffer(&dhcpv6_universe, opt_state,
				NULL, (unsigned char *)&lifetime, 4,
				D6O_CLT_TIME, 0)) {
		log_error("process_lq_by_address: error saving clt time.");
		goto exit;
	}

	/*
	 * Store the client-data option.
	 */
	opt_cursor = lq->cursor;
	putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA);
	lq->cursor += 2;
	/* Skip option length. */
	lq->cursor += 2;

	lq->cursor += store_options6((char *)lq->buf.data + lq->cursor,
				     sizeof(lq->buf) - lq->cursor,
				     opt_state, lq->packet,
				     required_opt_CLIENT_DATA, NULL);
	/* Reset the length. */
	putUShort(lq->buf.data + opt_cursor + 2,
		  lq->cursor - (opt_cursor + 4));

	/* Done. */
	ret_val = 1;

     exit:
	if (data.data != NULL)
		data_string_forget(&data, MDL);
	if (pool != NULL)
		ipv6_pool_dereference(&pool, MDL);
	if (iaaddr != NULL)
		iasubopt_dereference(&iaaddr, MDL);
	if (opt_state != NULL)
		option_state_dereference(&opt_state, MDL);
	return ret_val;
}