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