mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-25 11:37:56 +00:00
1f25327484
with minor changes to work around a bug in Cisco's IOS version 12.0 . 3.9-beta3 is much improved over 3.8, and is only labelled "beta" because of missing features, as opposed to instability or known bugs.
226 lines
6.0 KiB
C
226 lines
6.0 KiB
C
/*
|
|
* 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;
|
|
}
|