DragonFlyBSD Kernel Audit
DF-2610 / raw137listen.c
← back to finding ↓ download raw
/* raw137listen.c -- receive raw ICMPv6 type-139 messages with ancillary
 * IPV6_PKTINFO (src/dst) and IPV6_HOPLIMIT data. Used to observe what the
 * kernel actually did with our injected ND_REDIRECT (DF-2610 harness). */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int
main(int argc, char **argv)
{
	struct icmp6_filter filt;
	struct msghdr msg;
	struct iovec iov;
	struct cmsghdr *cmsg;
	struct sockaddr_in6 from;
	char cbuf[512], ip[64];
	uint8_t buf[2048];
	int s, n, secs = 3;
	struct timeval tv;

	if (argc > 1)
		secs = atoi(argv[1]);
	s = socket(AF_INET6, SOCK_RAW, 58);
	if (s < 0) {
		perror("socket");
		return 2;
	}
	ICMP6_FILTER_SETBLOCKALL(&filt);
	ICMP6_FILTER_SETPASS(137, &filt);
	setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt));
	n = 1;
	setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &n, sizeof(n));
	setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &n, sizeof(n));
	tv.tv_sec = secs;
	tv.tv_usec = 0;
	setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

	for (;;) {
		memset(&msg, 0, sizeof(msg));
		iov.iov_base = buf;
		iov.iov_len = sizeof(buf);
		msg.msg_iov = &iov;
		msg.msg_iovlen = 1;
		msg.msg_name = &from;
		msg.msg_namelen = sizeof(from);
		msg.msg_control = cbuf;
		msg.msg_controllen = sizeof(cbuf);
		n = recvmsg(s, &msg, 0);
		if (n < 0) {
			if (errno == EAGAIN)
				break;
			perror("recvmsg");
			break;
		}
		inet_ntop(AF_INET6, &from.sin6_addr, ip, sizeof(ip));
		printf("GOT %d bytes from %s scope=%u", n, ip,
		    from.sin6_scope_id);
		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
		    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
			if (cmsg->cmsg_level == IPPROTO_IPV6 &&
			    cmsg->cmsg_type == IPV6_PKTINFO) {
				struct in6_pktinfo *pi = (void *)CMSG_DATA(cmsg);
				char d[64];
				inet_ntop(AF_INET6, &pi->ipi6_addr, d, sizeof(d));
				printf(" dst=%s ifindex=%d", d, pi->ipi6_ifindex);
			} else if (cmsg->cmsg_level == IPPROTO_IPV6 &&
			    cmsg->cmsg_type == IPV6_HOPLIMIT) {
				int *hl = (void *)CMSG_DATA(cmsg);
				printf(" hlim=%d", *hl);
			}
		}
		printf(" icmp6{type=%u code=%u}\n", buf[0], buf[1]);
	}
	return 0;
}