Esempio n. 1
0
/* BPF requires that we read the entire buffer.
 * So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
if_readrawpacket(struct interface *ifp, int protocol,
    void *data, size_t len, int *flags)
{
	int fd;
	struct bpf_hdr packet;
	ssize_t bytes;
	const unsigned char *payload;
	struct dhcp_state *state;

	state = D_STATE(ifp);
	if (protocol == ETHERTYPE_ARP)
		fd = state->arp_fd;
	else
		fd = state->raw_fd;

	*flags = 0;
	for (;;) {
		if (state->buffer_len == 0) {
			bytes = read(fd, state->buffer, state->buffer_size);
			if (bytes == -1 || bytes == 0)
				return bytes;
			state->buffer_len = (size_t)bytes;
			state->buffer_pos = 0;
		}
		bytes = -1;
		memcpy(&packet, state->buffer + state->buffer_pos,
		    sizeof(packet));
		if (packet.bh_caplen != packet.bh_datalen)
			goto next; /* Incomplete packet, drop. */
		if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
		    state->buffer_len)
			goto next; /* Packet beyond buffer, drop. */
		payload = state->buffer + state->buffer_pos +
		    packet.bh_hdrlen + ETHER_HDR_LEN;
		bytes = (ssize_t)packet.bh_caplen - ETHER_HDR_LEN;
		if ((size_t)bytes > len)
			bytes = (ssize_t)len;
		memcpy(data, payload, (size_t)bytes);
next:
		state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
		    packet.bh_caplen);
		if (state->buffer_pos >= state->buffer_len) {
			state->buffer_len = state->buffer_pos = 0;
			*flags |= RAW_EOF;
		}
		if (bytes != -1)
			return bytes;
	}
}
Esempio n. 2
0
void
ipv4ll_start(void *arg)
{
	struct interface *ifp = arg;
	struct dhcp_state *state = D_STATE(ifp);
	uint32_t addr;

	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
	state->probes = 0;
	state->claims = 0;
	if (state->addr.s_addr) {
		state->conflicts = 0;
		if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
			arp_announce(ifp);
			return;
		}
	}

	if (state->offer == NULL)
		addr = 0;
	else {
		addr = state->offer->yiaddr;
		free(state->offer);
	}
	/* We maybe rebooting an IPv4LL address. */
	if (!IN_LINKLOCAL(htonl(addr))) {
		syslog(LOG_INFO, "%s: probing for an IPv4LL address",
		    ifp->name);
		addr = 0;
	}
	if (addr == 0)
		state->offer = ipv4ll_find_lease(addr);
	else
		state->offer = ipv4ll_make_lease(addr);
	if (state->offer == NULL)
		syslog(LOG_ERR, "%s: %m", __func__);
	else {
		state->lease.frominfo = 0;
		arp_probe(ifp);
	}
}
Esempio n. 3
0
void
ipv4ll_handle_failure(void *arg)
{
	struct interface *ifp = arg;
	struct dhcp_state *state = D_STATE(ifp);
	time_t up;

	if (state->fail.s_addr == state->addr.s_addr) {
		/* RFC 3927 Section 2.5 */
		up = uptime();
		if (state->defend + DEFEND_INTERVAL > up) {
			syslog(LOG_WARNING,
			    "%s: IPv4LL %d second defence failed",
			    ifp->name, DEFEND_INTERVAL);
			dhcp_drop(ifp, "EXPIRE");
			state->conflicts = -1;
		} else {
			syslog(LOG_DEBUG, "%s: defended IPv4LL address",
			    ifp->name);
			state->defend = up;
			return;
		}
	}

	free(state->offer);
	state->offer = NULL;
	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
	if (++state->conflicts > MAX_CONFLICTS) {
		syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
		    ifp->name);
		if (ifp->options->options & DHCPCD_DHCP) {
			state->interval = RATE_LIMIT_INTERVAL / 2;
			dhcp_discover(ifp);
		} else
			eloop_timeout_add_sec(ifp->ctx->eloop,
			    RATE_LIMIT_INTERVAL, ipv4ll_start, ifp);
	} else {
		eloop_timeout_add_sec(ifp->ctx->eloop,
		    PROBE_WAIT, ipv4ll_start, ifp);
	}
}
Esempio n. 4
0
int
if_openrawsocket(struct interface *ifp, int protocol)
{
	struct dhcp_state *state;
	int fd = -1;
	struct ifreq ifr;
	int ibuf_len = 0;
	size_t buf_len;
	struct bpf_version pv;
	struct bpf_program pf;
#ifdef BIOCIMMEDIATE
	int flags;
#endif
#ifdef _PATH_BPF
	fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC | O_NONBLOCK);
#else
	char device[32];
	int n = 0;

	do {
		snprintf(device, sizeof(device), "/dev/bpf%d", n++);
		fd = open(device, O_RDWR | O_CLOEXEC | O_NONBLOCK);
	} while (fd == -1 && errno == EBUSY);
#endif

	if (fd == -1)
		return -1;

	state = D_STATE(ifp);

	memset(&pv, 0, sizeof(pv));
	if (ioctl(fd, BIOCVERSION, &pv) == -1)
		goto eexit;
	if (pv.bv_major != BPF_MAJOR_VERSION ||
	    pv.bv_minor < BPF_MINOR_VERSION) {
		syslog(LOG_ERR, "BPF version mismatch - recompile");
		goto eexit;
	}

	memset(&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
	if (ioctl(fd, BIOCSETIF, &ifr) == -1)
		goto eexit;

	/* Get the required BPF buffer length from the kernel. */
	if (ioctl(fd, BIOCGBLEN, &ibuf_len) == -1)
		goto eexit;
	buf_len = (size_t)ibuf_len;
	if (state->buffer_size != buf_len) {
		free(state->buffer);
		state->buffer = malloc(buf_len);
		if (state->buffer == NULL)
			goto eexit;
		state->buffer_size = buf_len;
		state->buffer_len = state->buffer_pos = 0;
	}

#ifdef BIOCIMMEDIATE
	flags = 1;
	if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
		goto eexit;
#endif

	/* Install the DHCP filter */
	memset(&pf, 0, sizeof(pf));
	if (protocol == ETHERTYPE_ARP) {
		pf.bf_insns = UNCONST(arp_bpf_filter);
		pf.bf_len = arp_bpf_filter_len;
	} else {
		pf.bf_insns = UNCONST(dhcp_bpf_filter);
		pf.bf_len = dhcp_bpf_filter_len;
	}
	if (ioctl(fd, BIOCSETF, &pf) == -1)
		goto eexit;

	return fd;

eexit:
	free(state->buffer);
	state->buffer = NULL;
	close(fd);
	return -1;
}
Esempio n. 5
0
int
if_route(const struct rt *rt, int action)
{
	struct nlmr *nlm;
	int retval = 0;
	struct dhcp_state *state;

	nlm = calloc(1, sizeof(*nlm));
	if (nlm == NULL)
		return -1;
	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
	if (action == 0)
		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
	else if (action == 1)
		nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
	else
		nlm->hdr.nlmsg_type = RTM_DELROUTE;
	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
	nlm->rt.rtm_family = AF_INET;
	nlm->rt.rtm_table = RT_TABLE_MAIN;

	state = D_STATE(rt->iface);
	if (action == -1 || action == -2)
		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
	else {
		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
		/* We only change route metrics for kernel routes */
		if (rt->dest.s_addr ==
		    (state->addr.s_addr & state->net.s_addr) &&
		    rt->net.s_addr == state->net.s_addr)
			nlm->rt.rtm_protocol = RTPROT_KERNEL;
		else
			nlm->rt.rtm_protocol = RTPROT_BOOT;
		if (rt->gate.s_addr == INADDR_ANY ||
		    (rt->gate.s_addr == rt->dest.s_addr &&
			rt->net.s_addr == INADDR_BROADCAST))
			nlm->rt.rtm_scope = RT_SCOPE_LINK;
		else
			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
		nlm->rt.rtm_type = RTN_UNICAST;
	}

	nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
	    &rt->dest.s_addr, sizeof(rt->dest.s_addr));
	if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
		    &state->addr.s_addr, sizeof(state->addr.s_addr));
	}
	/* If destination == gateway then don't add the gateway */
	if (rt->dest.s_addr != rt->gate.s_addr ||
	    rt->net.s_addr != INADDR_BROADCAST)
		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));

	if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
		add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);

	if (send_netlink(&nlm->hdr) == -1)
		retval = -1;
	free(nlm);
	return retval;
}