/* * 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); }
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; } }