diff --git a/usr.sbin/mrouted/VERSION b/usr.sbin/mrouted/VERSION new file mode 100644 index 000000000000..a0ba149f7950 --- /dev/null +++ b/usr.sbin/mrouted/VERSION @@ -0,0 +1 @@ +3.9-beta3+IOS12 diff --git a/usr.sbin/mrouted/icmp.c b/usr.sbin/mrouted/icmp.c new file mode 100644 index 000000000000..72efa0ac745b --- /dev/null +++ b/usr.sbin/mrouted/icmp.c @@ -0,0 +1,225 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp + */ + +#include "defs.h" + +#ifndef lint +static char rcsid[] = "@(#) $Id: \ +icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp $"; +#endif + +static int icmp_socket; + +static void icmp_handler __P((int, fd_set *)); +static char * icmp_name __P((struct icmp *)); + +void +init_icmp() +{ + if ((icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) + log(LOG_ERR, errno, "ICMP socket"); + + register_input_handler(icmp_socket, icmp_handler); + + IF_DEBUG(DEBUG_ICMP) + log(LOG_DEBUG, 0, "registering icmp socket fd %d\n", icmp_socket); +} + +static void +icmp_handler(fd, rfds) + int fd; + fd_set *rfds; +{ + u_char icmp_buf[RECV_BUF_SIZE]; + struct sockaddr_in from; + int fromlen, recvlen, iphdrlen, ipdatalen; + struct icmp *icmp; + struct ip *ip; + vifi_t i; + struct uvif *v; + u_int32 src; + + fromlen = sizeof(from); + recvlen = recvfrom(icmp_socket, icmp_buf, RECV_BUF_SIZE, 0, + (struct sockaddr *)&from, &fromlen); + if (recvlen < 0) { + if (errno != EINTR) + log(LOG_WARNING, errno, "icmp_socket recvfrom"); + return; + } + ip = (struct ip *)icmp_buf; + iphdrlen = ip->ip_hl << 2; +#ifdef RAW_INPUT_IS_RAW + ipdatalen = ntohs(ip->ip_len) - iphdrlen; +#else + ipdatalen = ip->ip_len; +#endif + if (iphdrlen + ipdatalen != recvlen) { + IF_DEBUG(DEBUG_ICMP) + log(LOG_DEBUG, 0, "hdr %d data %d != rcv %d", iphdrlen, ipdatalen, recvlen); + /* Malformed ICMP, just return. */ + return; + } + if (ipdatalen < ICMP_MINLEN + sizeof(struct ip)) { + /* Not enough data for us to be interested in it. */ + return; + } + src = ip->ip_src.s_addr; + icmp = (struct icmp *)(icmp_buf + iphdrlen); + IF_DEBUG(DEBUG_ICMP) + log(LOG_DEBUG, 0, "got ICMP type %d from %s", + icmp->icmp_type, inet_fmt(src, s1)); + /* + * Eventually: + * have registry of ICMP listeners, by type, code and ICMP_ID + * (and maybe fields of the original packet too -- maybe need a + * generalized packet filter!) to allow ping and traceroute + * from the monitoring tool. + */ + switch (icmp->icmp_type) { + case ICMP_UNREACH: + case ICMP_TIMXCEED: + /* Look at returned packet to see if it's us sending on a tunnel */ + ip = &icmp->icmp_ip; + if (ip->ip_p != IPPROTO_IGMP && ip->ip_p != IPPROTO_IPIP) + return; + for (v = uvifs, i = 0; i < numvifs; v++, i++) { + if (ip->ip_src.s_addr == v->uv_lcl_addr && + ip->ip_dst.s_addr == v->uv_dst_addr) { + char *p; + int n; + /* + * I sent this packet on this vif. + */ + n = ++v->uv_icmp_warn; + while (n && !(n & 1)) + n >>= 1; + if (n == 1 && ((p = icmp_name(icmp)) != NULL)) + log(LOG_WARNING, 0, "Received ICMP %s from %s %s %s on vif %d", + p, inet_fmt(src, s1), "for traffic sent to", + inet_fmt(ip->ip_dst.s_addr, s2), + i); + + break; + } + } + break; + } +} + +/* + * Return NULL for ICMP informational messages. + * Return string describing the error for ICMP errors. + */ +static char * +icmp_name(icmp) + struct icmp *icmp; +{ + static char retval[30]; + + switch (icmp->icmp_type) { + case ICMP_UNREACH: + switch (icmp->icmp_code) { + case ICMP_UNREACH_NET: + return "network unreachable"; + case ICMP_UNREACH_HOST: + return "host unreachable"; + case ICMP_UNREACH_PROTOCOL: + return "protocol unreachable"; + case ICMP_UNREACH_PORT: + return "port unreachable"; + case ICMP_UNREACH_NEEDFRAG: + return "needs fragmentation"; + case ICMP_UNREACH_SRCFAIL: + return "source route failed"; +#ifndef ICMP_UNREACH_NET_UNKNOWN +#define ICMP_UNREACH_NET_UNKNOWN 6 +#endif + case ICMP_UNREACH_NET_UNKNOWN: + return "network unknown"; +#ifndef ICMP_UNREACH_HOST_UNKNOWN +#define ICMP_UNREACH_HOST_UNKNOWN 7 +#endif + case ICMP_UNREACH_HOST_UNKNOWN: + return "host unknown"; +#ifndef ICMP_UNREACH_ISOLATED +#define ICMP_UNREACH_ISOLATED 8 +#endif + case ICMP_UNREACH_ISOLATED: + return "source host isolated"; +#ifndef ICMP_UNREACH_NET_PROHIB +#define ICMP_UNREACH_NET_PROHIB 9 +#endif + case ICMP_UNREACH_NET_PROHIB: + return "network access prohibited"; +#ifndef ICMP_UNREACH_HOST_PROHIB +#define ICMP_UNREACH_HOST_PROHIB 10 +#endif + case ICMP_UNREACH_HOST_PROHIB: + return "host access prohibited"; +#ifndef ICMP_UNREACH_TOSNET +#define ICMP_UNREACH_TOSNET 11 +#endif + case ICMP_UNREACH_TOSNET: + return "bad TOS for net"; +#ifndef ICMP_UNREACH_TOSHOST +#define ICMP_UNREACH_TOSHOST 12 +#endif + case ICMP_UNREACH_TOSHOST: + return "bad TOS for host"; +#ifndef ICMP_UNREACH_FILTER_PROHIB +#define ICMP_UNREACH_FILTER_PROHIB 13 +#endif + case ICMP_UNREACH_FILTER_PROHIB: + return "prohibited by filter"; +#ifndef ICMP_UNREACH_HOST_PRECEDENCE +#define ICMP_UNREACH_HOST_PRECEDENCE 14 +#endif + case ICMP_UNREACH_HOST_PRECEDENCE: + return "host precedence violation"; +#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 +#endif + case ICMP_UNREACH_PRECEDENCE_CUTOFF: + return "precedence cutoff"; + default: + sprintf(retval, "unreachable code %d", icmp->icmp_code); + return retval; + } + case ICMP_SOURCEQUENCH: + return "source quench"; + case ICMP_REDIRECT: + return NULL; /* XXX */ + case ICMP_TIMXCEED: + switch (icmp->icmp_code) { + case ICMP_TIMXCEED_INTRANS: + return "time exceeded in transit"; + case ICMP_TIMXCEED_REASS: + return "time exceeded in reassembly"; + default: + sprintf(retval, "time exceeded code %d", icmp->icmp_code); + return retval; + } + case ICMP_PARAMPROB: + switch (icmp->icmp_code) { +#ifndef ICMP_PARAMPROB_OPTABSENT +#define ICMP_PARAMPROB_OPTABSENT 1 +#endif + case ICMP_PARAMPROB_OPTABSENT: + return "required option absent"; + default: + sprintf(retval, "parameter problem code %d", icmp->icmp_code); + return retval; + } + } + return NULL; +} diff --git a/usr.sbin/mrouted/igmpv2.h b/usr.sbin/mrouted/igmpv2.h new file mode 100644 index 000000000000..5f5ae27e68e8 --- /dev/null +++ b/usr.sbin/mrouted/igmpv2.h @@ -0,0 +1,42 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * igmpv2.h,v 3.8.4.1 1997/11/18 23:25:58 fenner Exp + */ + +/* + * Constants for IGMP Version 2. Several of these, especially the + * robustness variable, should be variables and not constants. + */ +#define IGMP_ROBUSTNESS_VARIABLE 2 +#define IGMP_QUERY_INTERVAL 125 +#define IGMP_QUERY_RESPONSE_INTERVAL 10 +#define IGMP_GROUP_MEMBERSHIP_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \ + IGMP_QUERY_INTERVAL + \ + IGMP_QUERY_RESPONSE_INTERVAL) +#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \ + IGMP_QUERY_INTERVAL + \ + IGMP_QUERY_RESPONSE_INTERVAL / 2) + /* Round to the nearest TIMER_INTERVAL */ +#define IGMP_STARTUP_QUERY_INTERVAL (((IGMP_QUERY_INTERVAL / 4) \ + / TIMER_INTERVAL) * TIMER_INTERVAL) +#define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE +#define IGMP_LAST_MEMBER_QUERY_INTERVAL 1 +#define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE + +/* + * OLD_AGE_THRESHOLD is the number of IGMP_QUERY_INTERVAL's to remember the + * presence of an IGMPv1 group member. According to the IGMPv2 specification, + * routers remember this presence for [Robustness Variable] * [Query Interval] + + * [Query Response Interval]. However, OLD_AGE_THRESHOLD is in units of + * [Query Interval], so doesn't have sufficient resolution to represent + * [Query Response Interval]. When the timer mechanism gets an efficient + * method of refreshing timers, this should get fixed. + */ +#define OLD_AGE_THRESHOLD IGMP_ROBUSTNESS_VARIABLE diff --git a/usr.sbin/mrouted/ipip.c b/usr.sbin/mrouted/ipip.c new file mode 100644 index 000000000000..6e88d932d3b4 --- /dev/null +++ b/usr.sbin/mrouted/ipip.c @@ -0,0 +1,145 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * ipip.c,v 3.8.4.6 1998/01/06 01:57:45 fenner Exp + */ + + +#include "defs.h" + +#ifndef lint +static char rcsid[] = "@(#) $Id: \ +ipip.c,v 3.8.4.6 1998/01/06 01:57:45 fenner Exp $"; +#endif + +/* + * Exported variables. + */ +#ifdef notyet +int raw_socket; /* socket for raw network I/O */ +#endif +/* + *XXX For now, we just use the IGMP socket to send packets. + * This is legal in BSD, because the protocol # is not checked + * on raw sockets. The k_* interfaces need to gain a socket + * argument so that we can call them on the raw_socket also. + */ +#define raw_socket igmp_socket + +/* + * Private variables. + */ +static int rawid = 0; + +/* + * Open and initialize the raw socket. + */ +void +init_ipip() +{ +#ifdef notyet + if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + log(LOG_ERR, errno, "Raw IP socket"); +#endif +} + +/* + * Allocate and fill in static IP header for encapsulating on a tunnel. + */ +void +init_ipip_on_vif(v) + struct uvif *v; +{ + struct ip *ip; + + ip = v->uv_encap_hdr = (struct ip *)malloc(sizeof(struct ip)); + if (ip == NULL) + log(LOG_ERR, 0, "out of memory"); + bzero(ip, sizeof(struct ip)); + /* + * Fields zeroed that aren't filled in later: + * - IP ID (let the kernel fill it in) + * - Offset (we don't send fragments) + * - Checksum (let the kernel fill it in) + */ + ip->ip_v = IPVERSION; + ip->ip_hl = sizeof(struct ip) >> 2; + ip->ip_tos = 0xc0; /* Internet Control */ + ip->ip_ttl = MAXTTL; /* applies to unicasts only */ + ip->ip_p = IPPROTO_IPIP; + ip->ip_src.s_addr = v->uv_lcl_addr; + ip->ip_dst.s_addr = v->uv_rmt_addr; +} + +/* + * Call build_igmp() to build an IGMP message in the output packet buffer. + * Then fill in the fields of the IP packet that build_igmp() left for the + * kernel to fill in, and encapsulate the original packet with the + * pre-created ip header for this vif. + */ +void +send_ipip(src, dst, type, code, group, datalen, v) + u_int32 src, dst; + int type, code; + u_int32 group; + int datalen; + struct uvif *v; +{ + struct msghdr msg; + struct iovec iov[2]; + struct sockaddr_in sdst; + struct ip *ip; + + build_igmp(src, dst, type, code, group, datalen); + ip = (struct ip *)send_buf; +#ifndef RAW_OUTPUT_IS_RAW + ip->ip_len = htons(ip->ip_len); +#endif + ip->ip_id = htons(rawid++); + ip->ip_sum = 0; + ip->ip_sum = inet_cksum((u_short *)ip, ip->ip_hl << 2); + + ip = v->uv_encap_hdr; + ip->ip_len = 2 * MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; +#ifdef RAW_OUTPUT_IS_RAW + ip->ip_len = htons(ip->ip_len); +#endif + + bzero(&sdst, sizeof(sdst)); + sdst.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + sdst.sin_len = sizeof(sdst); +#endif + sdst.sin_addr = ip->ip_dst; + + iov[0].iov_base = (caddr_t)v->uv_encap_hdr; + iov[0].iov_len = sizeof(struct ip); + iov[1].iov_base = (caddr_t)send_buf; + iov[1].iov_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; + + bzero(&msg, sizeof(msg)); + msg.msg_name = (caddr_t)&sdst; + msg.msg_namelen = sizeof(sdst); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + if (sendmsg(raw_socket, &msg, 0) < 0) { + if (errno == ENETDOWN) + check_vif_state(); + else + log(LOG_WARNING, errno, + "sendmsg to %s on %s", + inet_fmt(sdst.sin_addr.s_addr, s1), inet_fmt(src, s2)); + } + + IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code)) + log(LOG_DEBUG, 0, "SENT %s from %-15s to %s encaped to %s", + igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" : + inet_fmt(src, s1), inet_fmt(dst, s2), + inet_fmt(sdst.sin_addr.s_addr, s3)); +}