Adjust some perl & tcl related things in various scripts & utilities.
[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.4 2004/03/15 18:10:28 dillon Exp $
12  */
13
14 #include "defs.h"
15
16 static int      icmp_socket;
17
18 static void     icmp_handler(int, fd_set *);
19 static char *   icmp_name(struct icmp *);
20
21 void
22 init_icmp(void)
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(int fd, fd_set *rfds)
35 {
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;
44
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;
52     }
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;
65     }
66     if (ipdatalen < ICMP_MINLEN + sizeof(struct ip)) {
67         /* Not enough data for us to be interested in it. */
68         return;
69     }
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));
75     /*
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.
81      */
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;
94                     /*
95                      * I sent this packet on this vif.
96                      */
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),
104                             i);
105
106                     break;
107                 }
108             }
109             break;
110     }
111 }
112
113 /*
114  * Return NULL for ICMP informational messages.
115  * Return string describing the error for ICMP errors.
116  */
117 static char *
118 icmp_name(struct icmp *icmp)
119 {
120     static char retval[30];
121
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;
190             }
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;
204             }
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;
215             }
216     }
217     return NULL;
218 }