Beispiel #1
0
/*
 * Find the interface which received the given message.
 */
static uint_t
incoming_interface(struct msghdr *msg)
{
	void *opt;
	uint_t ifindex = 0;

	/*
	 * Determine which physical interface this packet was received on by
	 * processing the message's ancillary data to find the
	 * IP_RECVIF option we requested.
	 */
	if ((opt = find_ancillary(msg, IP_RECVIF)) == NULL)
		(void) fprintf(stderr,
		    gettext("%s: unable to retrieve input interface\n"),
		    pgmname);
	else
		ifindex = *(uint_t *)opt;
	return (ifindex);
}
Beispiel #2
0
void
in_data(struct phyint *pi)
{
	struct sockaddr_in6 from;
	struct icmp6_hdr *icmp;
	struct nd_router_solicit *rs;
	struct nd_router_advert *ra;
	static uint64_t in_packet[(IP_MAXPACKET + 1)/8];
	static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
	int len;
	char abuf[INET6_ADDRSTRLEN];
	const char *msgbuf;
	struct msghdr msg;
	struct iovec iov;
	uchar_t *opt;
	uint_t hoplimit;

	iov.iov_base = (char *)in_packet;
	iov.iov_len = sizeof (in_packet);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_name = (struct sockaddr *)&from;
	msg.msg_namelen = sizeof (from);
	msg.msg_control = ancillary_data;
	msg.msg_controllen = sizeof (ancillary_data);

	if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) {
		logperror_pi(pi, "in_data: recvfrom");
		return;
	}
	if (len == 0)
		return;

	if (inet_ntop(AF_INET6, (void *)&from.sin6_addr,
	    abuf, sizeof (abuf)) == NULL)
		msgbuf = "Unspecified Router";
	else
		msgbuf = abuf;

	/* Ignore packets > 64k or control buffers that don't fit */
	if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
		if (debug & D_PKTBAD) {
			logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x "
			    "from %s\n", msg.msg_flags, msgbuf);
		}
		return;
	}

	icmp = (struct icmp6_hdr *)in_packet;

	if (len < ICMP6_MINLEN) {
		logmsg(LOG_INFO, "Too short ICMP packet: %d bytes "
		    "from %s on %s\n",
		    len, msgbuf, pi->pi_name);
		return;
	}

	opt = find_ancillary(&msg, IPV6_HOPLIMIT);
	if (opt == NULL) {
		/* Unknown hoplimit - must drop */
		logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n",
		    msgbuf, pi->pi_name);
		return;
	}
	hoplimit = *(uint_t *)opt;
	opt = find_ancillary(&msg, IPV6_RTHDR);
	if (opt != NULL) {
		/* Can't allow routing headers in ND messages */
		logmsg(LOG_INFO, "ND message with routing header "
		    "from %s on %s\n",
		    msgbuf, pi->pi_name);
		return;
	}
	switch (icmp->icmp6_type) {
	case ND_ROUTER_SOLICIT:
		if (!pi->pi_AdvSendAdvertisements)
			return;
		if (pi->pi_flags & IFF_NORTEXCH) {
			if (debug & D_PKTIN) {
				logmsg(LOG_DEBUG, "Ignore received RS packet "
				    "on %s (no route exchange on interface)\n",
				    pi->pi_name);
			}
			return;
		}

		/*
		 * Assumes that the kernel has verified the AH (if present)
		 * and the ICMP checksum.
		 */
		if (hoplimit != IPV6_MAX_HOPS) {
			logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n",
			    hoplimit, msgbuf, pi->pi_name);
			return;
		}

		if (icmp->icmp6_code != 0) {
			logmsg(LOG_INFO, "RS code: %d from %s on %s\n",
			    icmp->icmp6_code, msgbuf, pi->pi_name);
			return;
		}

		if (len < sizeof (struct nd_router_solicit)) {
			logmsg(LOG_INFO, "RS too short: %d bytes "
			    "from %s on %s\n",
			    len, msgbuf, pi->pi_name);
			return;
		}
		rs = (struct nd_router_solicit *)icmp;
		if (len > sizeof (struct nd_router_solicit)) {
			if (!verify_opt_len((struct nd_opt_hdr *)&rs[1],
			    len - sizeof (struct nd_router_solicit), pi, &from))
				return;
		}
		if (debug & D_PKTIN) {
			print_route_sol("Received valid solicit from ", pi,
			    rs, len, &from);
		}
		incoming_rs(pi, rs, len, &from);
		break;

	case ND_ROUTER_ADVERT:
		if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
			/*
			 * Router advt. must have address!
			 * Logging the news and returning.
			 */
			logmsg(LOG_DEBUG,
			    "Router's address unspecified in advertisement\n");
			return;
		}
		if (pi->pi_flags & IFF_NORTEXCH) {
			if (debug & D_PKTIN) {
				logmsg(LOG_DEBUG, "Ignore received RA packet "
				    "on %s (no route exchange on interface)\n",
				    pi->pi_name);
			}
			return;
		}

		/*
		 * Assumes that the kernel has verified the AH (if present)
		 * and the ICMP checksum.
		 */
		if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
			logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n",
			    msgbuf, pi->pi_name);
			return;
		}

		if (hoplimit != IPV6_MAX_HOPS) {
			logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n",
			    hoplimit, msgbuf, pi->pi_name);
			return;
		}

		if (icmp->icmp6_code != 0) {
			logmsg(LOG_INFO, "RA code: %d from %s on %s\n",
			    icmp->icmp6_code, msgbuf, pi->pi_name);
			return;
		}

		if (len < sizeof (struct nd_router_advert)) {
			logmsg(LOG_INFO, "RA too short: %d bytes "
			    "from %s on %s\n",
			    len, msgbuf, pi->pi_name);
			return;
		}
		ra = (struct nd_router_advert *)icmp;
		if (len > sizeof (struct nd_router_advert)) {
			if (!verify_opt_len((struct nd_opt_hdr *)&ra[1],
			    len - sizeof (struct nd_router_advert), pi, &from))
				return;
		}
		if (debug & D_PKTIN) {
			print_route_adv("Received valid advert from ", pi,
			    ra, len, &from);
		}
		if (pi->pi_AdvSendAdvertisements)
			verify_ra_consistency(pi, ra, len, &from);
		else
			incoming_ra(pi, ra, len, &from, _B_FALSE);
		break;
	}
}