Beispiel #1
0
static void nl_parse_link_msg(struct nlmsghdr *nlp, struct nl_cb *cb)
{
	nl_link_cb link_cb;
	struct ifinfomsg *ifinfo;
	struct rtattr *rtap;
	struct nl_link link;
	size_t len;

	memset(&link, 0, sizeof(struct nl_link));
	ifinfo = NLMSG_DATA(nlp);
	rtap = IFLA_RTA(ifinfo);
	len = IFLA_PAYLOAD(nlp);

	for (; RTA_OK(rtap, len); rtap = RTA_NEXT(rtap, len)) {
		switch (rtap->rta_type) {
		case IFLA_IFNAME:
			link.ifname = (char *)RTA_DATA(rtap);
			break;
		case IFLA_ADDRESS:
			if (RTA_PAYLOAD(rtap) != sizeof(struct ether_addr)) {
				XLOG_ERR("invalid ll address for %u", ifinfo->ifi_index);
				return;
			}
			link.ifaddr = (struct ether_addr *)RTA_DATA(rtap);
			break;
		default:
			/* XLOG_DEBUG("attr: %u", rtap->rta_type); */
			break;
		}
	}

	if (!link.ifname) {
		XLOG_ERR("could not get name for link %u", ifinfo->ifi_index);
		return;
	}

	if (!link.ifaddr) {
		XLOG_ERR("could not get ll addr for link %u", ifinfo->ifi_index);
		return;
	}

	link.ifindex = ifinfo->ifi_index;
	link.iftype = ifinfo->ifi_type;
	link.ifflags = ifinfo->ifi_flags;

	link_cb = (nl_link_cb) cb->parse_cb;
	link_cb(&link, cb->aux);
}
Beispiel #2
0
int daemonize()
{
	pid_t pid = fork();
	if (pid < 0) {
		exit(EXIT_FAILURE);
	}

	if (pid > 0) {
		exit(EXIT_SUCCESS);
	}

	if (write_pidfile() != 0) {
		return -1;
	}

	int ret = setsid();
	if (ret == -1) {
		XLOG_ERR("failed to set session id: %s", strerror(errno));
		unlink(PIDFILE);
		return -1;
	}

	for (int fd = getdtablesize(); fd >= 0; --fd) {
		 close(fd);
	}

	chdir("/");

	int fd = open("/dev/null", O_RDWR);
	dup(fd);
	dup(fd);

	return 0;
}
Beispiel #3
0
bool setup_link(struct link *link, void *aux)
{
	int fd = open_socket();
	if (fd < 0) {
		goto err;
	}

	if (do_bind(fd, link->ifindex) != 0) {
		goto err;
	}

	if (set_promisc(fd, link->ifindex) != 0) {
		goto err;
	}

	struct dispatcher *dispatcher = (struct dispatcher *) aux;
	link->handler = dispatcher_watch(
		dispatcher, fd, rarp_handler, link);
	dispatcher_flags(&link->handler, POLLIN);

	return true;
err:
	close(fd);
	XLOG_ERR("error setting up %s", link->name);
	return false;
}
Beispiel #4
0
static bool nl_parse(char *buf, ssize_t len, struct nl_cb *cb)
{
	struct nlmsghdr *nlp;
	struct nlmsgerr *err;

	nlp = (struct nlmsghdr *) buf;
	for(;NLMSG_OK(nlp, len);nlp=NLMSG_NEXT(nlp, len)) {
		switch (nlp->nlmsg_type) {
		case NLMSG_ERROR:
			err = (struct nlmsgerr *) NLMSG_DATA(nlp);
			XLOG_ERR("received netlink error %s", strerror(-err->error));
		case NLMSG_DONE:
			return false;
		default:
			if (nlp->nlmsg_type == cb->msg_type) {
				cb->parse_msg(nlp, cb);
				break;
			}
			XLOG_DEBUG("unhandled netlink message of type %u", nlp->nlmsg_type);
			break;
		}
		if (!(nlp->nlmsg_flags & NLM_F_MULTI)) {
			return false;
		}
	}
	return true;
}
Beispiel #5
0
static void nl_parse_addr_msg(struct nlmsghdr *nlp, struct nl_cb *cb)
{
	struct ifaddrmsg *ifaddr;
	struct rtattr *rtap;
	nl_addr_cb addr_cb;
	size_t len;
	in_addr_t *addr;
	struct nl_addr nl_addr;

	addr = NULL;
	ifaddr = NLMSG_DATA(nlp);
	rtap = IFLA_RTA(ifaddr);
	len = IFLA_PAYLOAD(nlp);

	for (; RTA_OK(rtap, len); rtap = RTA_NEXT(rtap, len)) {
		switch (rtap->rta_type) {
		case IFA_LOCAL:
			addr = (in_addr_t*)RTA_DATA(rtap);
			break;
		default:
			break;
		}
	}

	if (!addr) {
		XLOG_ERR("could not get addr for link %u", ifaddr->ifa_index);
		return;
	}

	addr_cb = (nl_addr_cb) cb->parse_cb;
	nl_addr.ifindex = ifaddr->ifa_index;
	nl_addr.ifaddr = *addr;
	addr_cb(&nl_addr , cb->aux);
}
Beispiel #6
0
int open_socket()
{
	int fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_RARP));
	if (fd < 0) {
		XLOG_ERR("error opening socket %s", strerror(errno));
		return -1;
	}

	if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) {
		XLOG_ERR("error setting socket nonblocking %s",
			strerror(errno));
		close(fd);
		return -1;
	}

	return fd;
}
Beispiel #7
0
int write_pidfile()
{
	int fd = open(PIDFILE, O_WRONLY|O_CLOEXEC|O_CREAT|O_EXCL, 0644);
	if (fd < 0) {
		XLOG_ERR("could not open pidfile: %s", strerror(errno));
		return -1;
	}

	FILE *pidfile = fdopen(fd, "w");
	if (pidfile == NULL) {
		XLOG_ERR("could not fdopen pidfile: %s", strerror(errno));
		return -1;
	}

	fprintf(pidfile, "%u", getpid());
	fclose(pidfile);

	return 0;
}
Beispiel #8
0
int nl_open(struct nl_ctx *nl_ctx)
{
	int ret;

	nl_ctx->fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
	if (nl_ctx->fd < 0)  {
		XLOG_ERR("error opening netlink socket: %s", strerror(errno));
		return -1;
	}

	memset(&nl_ctx->sa, 0, sizeof(struct sockaddr_nl));
	nl_ctx->sa.nl_family = AF_NETLINK;
	nl_ctx->sa.nl_pid = 0;
	nl_ctx->sa.nl_groups = 0;

	ret = bind(nl_ctx->fd, (struct sockaddr *) &nl_ctx->sa, sizeof(struct sockaddr_nl));
	if (ret < 0)  {
		XLOG_ERR("error binding netlink socket: %s", strerror(errno));
		return -1;
	}

	return 0;
}
Beispiel #9
0
static enum dispatch_action
dispatch(struct poll_handler *handler, struct pollfd *pollfd)
{
	if (pollfd->revents == 0) {
		return DISPATCH_CONTINUE;
	}

	if (pollfd->revents & POLLERR) {
		XLOG_ERR("poll error on fd %i", pollfd->fd);
		return DISPATCH_ABORT;
	}

	return handler->handler(pollfd->fd, pollfd->events, handler->aux);
}
Beispiel #10
0
ssize_t read_request(int fd, struct sockaddr_ll *addr, char *buf, size_t size)
{
	socklen_t addrlen = sizeof(struct sockaddr_ll);
	ssize_t ret = recvfrom(fd, buf, size, 0, (struct sockaddr *)addr, &addrlen);
	if (ret < 0) {
		if (errno == EAGAIN || errno == EWOULDBLOCK) {
			return 0;
		}
		XLOG_ERR("read error on fd %i: %s", fd, strerror(errno));
		return -1;
	}

	XLOG_DEBUG("read %zi octets", ret);
	return ret;
}
Beispiel #11
0
int nl_list_links(struct nl_ctx *nl_ctx)
{
	int ret;
	size_t size;
	char buf[1024];

	size = nl_create_msg(buf, sizeof(buf), RTM_GETLINK, NLM_F_REQUEST|NLM_F_DUMP, PF_PACKET);
	ret = send(nl_ctx->fd, buf, size, 0);
	if (ret != size) {
		XLOG_ERR("error sending netlink message: %s", strerror(errno));
		return -1;
	}

	return 0;
}
Beispiel #12
0
int send_reply(int fd, struct link *link)
{
	ssize_t ret = sendto(fd, link->buf, sizeof(struct ether_arp), 0,
		(struct sockaddr *)&link->src, sizeof(struct sockaddr_ll));
	if (ret < 0) {
		if (errno == EAGAIN || errno == EWOULDBLOCK) {
			return 0;
		}
		XLOG_ERR("write error on fd %i: %s", fd, strerror(errno));
		return -1;
	}

	XLOG_DEBUG("send %zi octets on %s", ret, link->name);
	dispatcher_flags(&link->handler, POLLIN);
	return 0;
}
Beispiel #13
0
int do_bind(int fd, size_t ifindex)
{
	struct sockaddr_ll addr;
	memset(&addr, 0, sizeof(struct sockaddr_ll));
	addr.sll_family = PF_PACKET;
	addr.sll_ifindex = ifindex;

	int ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll));
	if (ret == -1) {
		XLOG_ERR("error binding socket on %zu: %s",
			ifindex, strerror(errno));
		return -1;
	}

	return 0;
}
Beispiel #14
0
int nl_receive(struct nl_ctx *nl_ctx, struct nl_cb *cb)
{
	char buf[32768];
	ssize_t len;

	do {
		memset(buf, 0, sizeof(buf));
		len = recv(nl_ctx->fd, buf, sizeof(buf), 0);
		if (len < 0) {
			XLOG_ERR("error receiving netlink message: %s", strerror(errno));
			return -1;
		}
	} while (nl_parse(buf, len, cb));

	return 0;
}
Beispiel #15
0
int set_promisc(int fd, size_t ifindex)
{
	struct packet_mreq mreq;
	memset(&mreq, 0, sizeof(struct packet_mreq));
	mreq.mr_ifindex = ifindex;
	mreq.mr_type = PACKET_MR_PROMISC;

	int ret = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
		&mreq, sizeof(struct packet_mreq));
	if (ret != 0) {
		XLOG_ERR("error setting promisc mode on link %zu: %s",
			ifindex, strerror(errno));
		return -1;
	}

	return 0;
}
Beispiel #16
0
int rarpd(int argc, char *argv[])
{
	struct rarpd rarpd;
	rarpd_init(&rarpd);

	if (parse_options(&rarpd, argc, argv) != 0) {
		return EXIT_FAILURE;
	}

	if (parse_args(&rarpd, argv) != 0) {
		return EXIT_FAILURE;
	}

	if (!(rarpd.opts & FOREGROUND) && daemonize() != 0) {
		return EXIT_FAILURE;
	}

	init_syslog(&rarpd);

	if (rarpd_init_signals(&rarpd) != 0) {
		return EXIT_FAILURE;
	}

	if (find_interfaces(&rarpd) != 0) {
		return EXIT_FAILURE;
	}

	link_array_filter(&rarpd.links, has_addr, NULL);
	if (rarpd.links.count == 0) {
		XLOG_ERR("no usable links found");
		return EXIT_FAILURE;
	}

	if (!link_array_foreach(&rarpd.links, setup_link, &rarpd.dispatcher)) {
		cleanup_rarpd(&rarpd);
		return EXIT_FAILURE;
	}

	dispatcher_run(&rarpd.dispatcher);

	cleanup_rarpd(&rarpd);
	return EXIT_SUCCESS;
}
Beispiel #17
0
int dispatcher_run(struct dispatcher *dispatcher)
{
	int ret;

	for(;;) {
		foreach_handler(dispatcher, set_events);

		do {
			ret = poll(dispatcher->fds, dispatcher->nfds, -1);
		} while (ret < 0 && errno == EINTR);

		if (ret < 0) {
			XLOG_ERR("poll error: %s", strerror(errno));
			return -1;
		}

		if (foreach_handler(dispatcher, dispatch) == DISPATCH_ABORT) {
			return 0;
		}
	}
}
Beispiel #18
0
int nl_set_neigh(struct nl_ctx *nl_ctx, size_t index, struct ether_addr *ether_addr, in_addr_t *in_addr)
{
	int ret;
	size_t size;
	char buf[1024];

	size = nl_create_msg(buf, sizeof(buf), RTM_NEWNEIGH,
		NLM_F_REQUEST|NLM_F_REPLACE|NLM_F_CREATE, PF_INET);
	// nl_add_attr((struct nlmsghdr *) data, NDA_DST, sizeof(in_addr_r), in_addr);
	// nl_add_attr((struct nlmsghdr *) data, NDA_LLADDR, sizeof(struct ether_addr), ether_addr);
	// fill in ndm_ifindex from link
	// set ndm_state NUD_PERMANENT

	ret = send(nl_ctx->fd, buf, size, 0);
	if (ret != size) {
		XLOG_ERR("error sending netlink message: %s", strerror(errno));
		return -1;
	}

	return 0;
}