MFC r1.6 r1.30 r1.28 (HEAD):
[dragonfly.git] / usr.sbin / mrouted / icmp.c
blob129e6748424fc1d951f9d518fa6d495222433964
1 /*
2 * The mrouted program is covered by the license in the accompanying file
3 * named "LICENSE". Use of the mrouted program represents acceptance of
4 * the terms and conditions listed in that file.
6 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7 * Leland Stanford Junior University.
10 * @(#) $Id icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp $
11 * $DragonFly: src/usr.sbin/mrouted/icmp.c,v 1.4 2004/03/15 18:10:28 dillon Exp $
14 #include "defs.h"
16 static int icmp_socket;
18 static void icmp_handler(int, fd_set *);
19 static char * icmp_name(struct icmp *);
21 void
22 init_icmp(void)
24 if ((icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
25 log(LOG_ERR, errno, "ICMP socket");
27 register_input_handler(icmp_socket, icmp_handler);
29 IF_DEBUG(DEBUG_ICMP)
30 log(LOG_DEBUG, 0, "registering icmp socket fd %d\n", icmp_socket);
33 static void
34 icmp_handler(int fd, fd_set *rfds)
36 u_char icmp_buf[RECV_BUF_SIZE];
37 struct sockaddr_in from;
38 int fromlen, recvlen, iphdrlen, ipdatalen;
39 struct icmp *icmp;
40 struct ip *ip;
41 vifi_t i;
42 struct uvif *v;
43 u_int32 src;
45 fromlen = sizeof(from);
46 recvlen = recvfrom(icmp_socket, icmp_buf, RECV_BUF_SIZE, 0,
47 (struct sockaddr *)&from, &fromlen);
48 if (recvlen < 0) {
49 if (errno != EINTR)
50 log(LOG_WARNING, errno, "icmp_socket recvfrom");
51 return;
53 ip = (struct ip *)icmp_buf;
54 iphdrlen = ip->ip_hl << 2;
55 #ifdef RAW_INPUT_IS_RAW
56 ipdatalen = ntohs(ip->ip_len) - iphdrlen;
57 #else
58 ipdatalen = ip->ip_len;
59 #endif
60 if (iphdrlen + ipdatalen != recvlen) {
61 IF_DEBUG(DEBUG_ICMP)
62 log(LOG_DEBUG, 0, "hdr %d data %d != rcv %d", iphdrlen, ipdatalen, recvlen);
63 /* Malformed ICMP, just return. */
64 return;
66 if (ipdatalen < ICMP_MINLEN + sizeof(struct ip)) {
67 /* Not enough data for us to be interested in it. */
68 return;
70 src = ip->ip_src.s_addr;
71 icmp = (struct icmp *)(icmp_buf + iphdrlen);
72 IF_DEBUG(DEBUG_ICMP)
73 log(LOG_DEBUG, 0, "got ICMP type %d from %s",
74 icmp->icmp_type, inet_fmt(src, s1));
76 * Eventually:
77 * have registry of ICMP listeners, by type, code and ICMP_ID
78 * (and maybe fields of the original packet too -- maybe need a
79 * generalized packet filter!) to allow ping and traceroute
80 * from the monitoring tool.
82 switch (icmp->icmp_type) {
83 case ICMP_UNREACH:
84 case ICMP_TIMXCEED:
85 /* Look at returned packet to see if it's us sending on a tunnel */
86 ip = &icmp->icmp_ip;
87 if (ip->ip_p != IPPROTO_IGMP && ip->ip_p != IPPROTO_IPIP)
88 return;
89 for (v = uvifs, i = 0; i < numvifs; v++, i++) {
90 if (ip->ip_src.s_addr == v->uv_lcl_addr &&
91 ip->ip_dst.s_addr == v->uv_dst_addr) {
92 char *p;
93 int n;
95 * I sent this packet on this vif.
97 n = ++v->uv_icmp_warn;
98 while (n && !(n & 1))
99 n >>= 1;
100 if (n == 1 && ((p = icmp_name(icmp)) != NULL))
101 log(LOG_WARNING, 0, "Received ICMP %s from %s %s %s on vif %d",
102 p, inet_fmt(src, s1), "for traffic sent to",
103 inet_fmt(ip->ip_dst.s_addr, s2),
106 break;
109 break;
114 * Return NULL for ICMP informational messages.
115 * Return string describing the error for ICMP errors.
117 static char *
118 icmp_name(struct icmp *icmp)
120 static char retval[30];
122 switch (icmp->icmp_type) {
123 case ICMP_UNREACH:
124 switch (icmp->icmp_code) {
125 case ICMP_UNREACH_NET:
126 return "network unreachable";
127 case ICMP_UNREACH_HOST:
128 return "host unreachable";
129 case ICMP_UNREACH_PROTOCOL:
130 return "protocol unreachable";
131 case ICMP_UNREACH_PORT:
132 return "port unreachable";
133 case ICMP_UNREACH_NEEDFRAG:
134 return "needs fragmentation";
135 case ICMP_UNREACH_SRCFAIL:
136 return "source route failed";
137 #ifndef ICMP_UNREACH_NET_UNKNOWN
138 #define ICMP_UNREACH_NET_UNKNOWN 6
139 #endif
140 case ICMP_UNREACH_NET_UNKNOWN:
141 return "network unknown";
142 #ifndef ICMP_UNREACH_HOST_UNKNOWN
143 #define ICMP_UNREACH_HOST_UNKNOWN 7
144 #endif
145 case ICMP_UNREACH_HOST_UNKNOWN:
146 return "host unknown";
147 #ifndef ICMP_UNREACH_ISOLATED
148 #define ICMP_UNREACH_ISOLATED 8
149 #endif
150 case ICMP_UNREACH_ISOLATED:
151 return "source host isolated";
152 #ifndef ICMP_UNREACH_NET_PROHIB
153 #define ICMP_UNREACH_NET_PROHIB 9
154 #endif
155 case ICMP_UNREACH_NET_PROHIB:
156 return "network access prohibited";
157 #ifndef ICMP_UNREACH_HOST_PROHIB
158 #define ICMP_UNREACH_HOST_PROHIB 10
159 #endif
160 case ICMP_UNREACH_HOST_PROHIB:
161 return "host access prohibited";
162 #ifndef ICMP_UNREACH_TOSNET
163 #define ICMP_UNREACH_TOSNET 11
164 #endif
165 case ICMP_UNREACH_TOSNET:
166 return "bad TOS for net";
167 #ifndef ICMP_UNREACH_TOSHOST
168 #define ICMP_UNREACH_TOSHOST 12
169 #endif
170 case ICMP_UNREACH_TOSHOST:
171 return "bad TOS for host";
172 #ifndef ICMP_UNREACH_FILTER_PROHIB
173 #define ICMP_UNREACH_FILTER_PROHIB 13
174 #endif
175 case ICMP_UNREACH_FILTER_PROHIB:
176 return "prohibited by filter";
177 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
178 #define ICMP_UNREACH_HOST_PRECEDENCE 14
179 #endif
180 case ICMP_UNREACH_HOST_PRECEDENCE:
181 return "host precedence violation";
182 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
183 #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
184 #endif
185 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
186 return "precedence cutoff";
187 default:
188 sprintf(retval, "unreachable code %d", icmp->icmp_code);
189 return retval;
191 case ICMP_SOURCEQUENCH:
192 return "source quench";
193 case ICMP_REDIRECT:
194 return NULL; /* XXX */
195 case ICMP_TIMXCEED:
196 switch (icmp->icmp_code) {
197 case ICMP_TIMXCEED_INTRANS:
198 return "time exceeded in transit";
199 case ICMP_TIMXCEED_REASS:
200 return "time exceeded in reassembly";
201 default:
202 sprintf(retval, "time exceeded code %d", icmp->icmp_code);
203 return retval;
205 case ICMP_PARAMPROB:
206 switch (icmp->icmp_code) {
207 #ifndef ICMP_PARAMPROB_OPTABSENT
208 #define ICMP_PARAMPROB_OPTABSENT 1
209 #endif
210 case ICMP_PARAMPROB_OPTABSENT:
211 return "required option absent";
212 default:
213 sprintf(retval, "parameter problem code %d", icmp->icmp_code);
214 return retval;
217 return NULL;