use pfctlinput instead of ip_ctlinput to hit everyone
[unix-history] / usr / src / sys / netinet / ip_icmp.c
CommitLineData
0270e817 1/* ip_icmp.c 6.11 85/05/27 */
81a36a8d 2
20666ad3
JB
3#include "param.h"
4#include "systm.h"
5#include "mbuf.h"
6#include "protosw.h"
7#include "socket.h"
8#include "time.h"
9#include "kernel.h"
6e7edb25
BJ
10
11#include "../net/route.h"
c175a1bd 12#include "../net/if.h"
f4d55810 13
20666ad3
JB
14#include "in.h"
15#include "in_systm.h"
c175a1bd 16#include "in_var.h"
20666ad3
JB
17#include "ip.h"
18#include "ip_icmp.h"
19#include "icmp_var.h"
81a36a8d 20
a60889ab 21#ifdef ICMPPRINTFS
81a36a8d
BJ
22/*
23 * ICMP routines: error generation, receive packet processing, and
24 * routines to turnaround packets back to the originator, and
25 * host table maintenance routines.
26 */
67387c9c 27int icmpprintfs = 0;
a60889ab 28#endif
81a36a8d
BJ
29
30/*
72e4f44e
SL
31 * Generate an error packet of type error
32 * in response to bad packet ip.
81a36a8d
BJ
33 */
34icmp_error(oip, type, code)
35 struct ip *oip;
755d8841 36 int type, code;
81a36a8d 37{
72e4f44e
SL
38 register unsigned oiplen = oip->ip_hl << 2;
39 register struct icmp *icp;
81a36a8d
BJ
40 struct mbuf *m;
41 struct ip *nip;
42
a60889ab 43#ifdef ICMPPRINTFS
39674d5f
SL
44 if (icmpprintfs)
45 printf("icmp_error(%x, %d, %d)\n", oip, type, code);
a60889ab 46#endif
7b66c1fd 47 icmpstat.icps_error++;
81a36a8d
BJ
48 /*
49 * Make sure that the old IP packet had 8 bytes of data to return;
50 * if not, don't bother. Also don't EVER error if the old
51 * packet protocol was ICMP.
52 */
7b66c1fd
SL
53 if (oip->ip_len < 8) {
54 icmpstat.icps_oldshort++;
81a36a8d 55 goto free;
7b66c1fd
SL
56 }
57 if (oip->ip_p == IPPROTO_ICMP) {
58 icmpstat.icps_oldicmp++;
59 goto free;
60 }
81a36a8d
BJ
61
62 /*
72e4f44e 63 * First, formulate icmp message
81a36a8d 64 */
cce93e4b 65 m = m_get(M_DONTWAIT, MT_HEADER);
7b66c1fd 66 if (m == NULL)
81a36a8d 67 goto free;
72e4f44e
SL
68 m->m_len = oiplen + 8 + ICMP_MINLEN;
69 m->m_off = MMAXOFF - m->m_len;
70 icp = mtod(m, struct icmp *);
755d8841 71 if ((u_int)type > ICMP_IREQREPLY)
7b66c1fd
SL
72 panic("icmp_error");
73 icmpstat.icps_outhist[type]++;
81a36a8d 74 icp->icmp_type = type;
72e4f44e 75 icp->icmp_void = 0;
81a36a8d 76 if (type == ICMP_PARAMPROB) {
81a36a8d 77 icp->icmp_pptr = code;
72e4f44e
SL
78 code = 0;
79 }
80 icp->icmp_code = code;
d52566dd 81 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
39674d5f
SL
82 nip = &icp->icmp_ip;
83 nip->ip_len += oiplen;
39674d5f 84 nip->ip_len = htons((u_short)nip->ip_len);
81a36a8d
BJ
85
86 /*
72e4f44e
SL
87 * Now, copy old ip header in front of icmp
88 * message. This allows us to reuse any source
89 * routing info present.
81a36a8d 90 */
72e4f44e
SL
91 m->m_off -= oiplen;
92 nip = mtod(m, struct ip *);
93 bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
94 nip->ip_len = m->m_len + oiplen;
95 nip->ip_p = IPPROTO_ICMP;
96 /* icmp_send adds ip header to m_off and m_len, so we deduct here */
97 m->m_off += oiplen;
d52566dd 98 icmp_reflect(nip);
81a36a8d 99
def04636 100free:
81a36a8d
BJ
101 m_freem(dtom(oip));
102}
103
72e4f44e
SL
104static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
105static struct sockaddr_in icmpsrc = { AF_INET };
106static struct sockaddr_in icmpdst = { AF_INET };
107
81a36a8d 108/*
d52566dd 109 * Process a received ICMP message.
81a36a8d
BJ
110 */
111icmp_input(m)
112 struct mbuf *m;
113{
81a36a8d 114 register struct icmp *icp;
d52566dd 115 register struct ip *ip = mtod(m, struct ip *);
af8f6a21 116 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
8046f415
MK
117 register int i;
118 int (*ctlfunc)(), code;
b454c3ea 119 extern u_char ip_protox[];
c175a1bd 120 extern struct in_addr in_makeaddr();
81a36a8d
BJ
121
122 /*
123 * Locate icmp structure in mbuf, and check
124 * that not corrupted and of at least minimum length.
125 */
a60889ab 126#ifdef ICMPPRINTFS
39674d5f
SL
127 if (icmpprintfs)
128 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
a60889ab 129#endif
4d75f980 130 if (icmplen < ICMP_MINLEN) {
7b66c1fd 131 icmpstat.icps_tooshort++;
72e4f44e 132 goto free;
7b66c1fd 133 }
8046f415
MK
134 /* THIS LENGTH CHECK STILL MISSES ANY IP OPTIONS IN ICMP_IP */
135 i = MIN(icmplen, ICMP_ADVLENMIN + hlen);
136 if ((m->m_off > MMAXOFF || m->m_len < i) &&
137 (m = m_pullup(m, i)) == 0) {
167351c2
MK
138 icmpstat.icps_tooshort++;
139 return;
140 }
8046f415 141 ip = mtod(m, struct ip *);
81a36a8d
BJ
142 m->m_len -= hlen;
143 m->m_off += hlen;
72e4f44e 144 icp = mtod(m, struct icmp *);
8046f415 145 if (in_cksum(m, icmplen)) {
7b66c1fd 146 icmpstat.icps_checksum++;
d52566dd 147 goto free;
72e4f44e 148 }
81a36a8d 149
a60889ab 150#ifdef ICMPPRINTFS
81a36a8d
BJ
151 /*
152 * Message type specific processing.
153 */
39674d5f
SL
154 if (icmpprintfs)
155 printf("icmp_input, type %d code %d\n", icp->icmp_type,
a60889ab
KM
156 icp->icmp_code);
157#endif
7b66c1fd
SL
158 if (icp->icmp_type > ICMP_IREQREPLY)
159 goto free;
160 icmpstat.icps_inhist[icp->icmp_type]++;
a60889ab 161 code = icp->icmp_code;
7b66c1fd 162 switch (icp->icmp_type) {
81a36a8d
BJ
163
164 case ICMP_UNREACH:
a60889ab
KM
165 if (code > 5)
166 goto badcode;
167 code += PRC_UNREACH_NET;
168 goto deliver;
169
81a36a8d 170 case ICMP_TIMXCEED:
a60889ab
KM
171 if (code > 1)
172 goto badcode;
173 code += PRC_TIMXCEED_INTRANS;
174 goto deliver;
175
81a36a8d 176 case ICMP_PARAMPROB:
a60889ab
KM
177 if (code)
178 goto badcode;
179 code = PRC_PARAMPROB;
180 goto deliver;
181
72e4f44e 182 case ICMP_SOURCEQUENCH:
a60889ab
KM
183 if (code)
184 goto badcode;
185 code = PRC_QUENCH;
186 deliver:
81a36a8d 187 /*
a60889ab 188 * Problem with datagram; advise higher level routines.
81a36a8d 189 */
a1edc12b 190 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
7b66c1fd
SL
191 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
192 icmpstat.icps_badlen++;
d52566dd 193 goto free;
7b66c1fd 194 }
a60889ab 195#ifdef ICMPPRINTFS
39674d5f
SL
196 if (icmpprintfs)
197 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
a60889ab 198#endif
59965020 199 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
a60889ab
KM
200 (*ctlfunc)(code, (caddr_t)icp);
201 goto free;
202
203 badcode:
204 icmpstat.icps_badcode++;
81a36a8d
BJ
205 goto free;
206
207 case ICMP_ECHO:
208 icp->icmp_type = ICMP_ECHOREPLY;
209 goto reflect;
210
211 case ICMP_TSTAMP:
7b66c1fd
SL
212 if (icmplen < ICMP_TSLEN) {
213 icmpstat.icps_badlen++;
d52566dd 214 goto free;
7b66c1fd 215 }
81a36a8d 216 icp->icmp_type = ICMP_TSTAMPREPLY;
2b4b57cd 217 icp->icmp_rtime = iptime();
81a36a8d
BJ
218 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
219 goto reflect;
220
221 case ICMP_IREQ:
c175a1bd
MK
222#define satosin(sa) ((struct sockaddr_in *)(sa))
223 if (in_netof(ip->ip_src) == 0)
224 ip->ip_src = in_makeaddr(
225 in_netof(satosin(&in_ifaddr->ia_addr)->sin_addr),
226 in_lnaof(ip->ip_src));
227 icp->icmp_type = ICMP_IREQREPLY;
81a36a8d
BJ
228 goto reflect;
229
a469458a 230 case ICMP_REDIRECT:
7b66c1fd
SL
231 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
232 icmpstat.icps_badlen++;
d52566dd 233 goto free;
7b66c1fd 234 }
a469458a
SL
235 /*
236 * Short circuit routing redirects to force
237 * immediate change in the kernel's routing
238 * tables. The message is also handed to anyone
239 * listening on a raw socket (e.g. the routing
fbc81152 240 * daemon for use in updating its tables).
a469458a 241 */
167351c2 242 icmpdst.sin_addr = icp->icmp_gwaddr;
fbc81152
MK
243 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
244 icmpsrc.sin_addr =
c175a1bd 245 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
fbc81152
MK
246 rtredirect((struct sockaddr *)&icmpsrc,
247 (struct sockaddr *)&icmpdst, RTF_GATEWAY);
0270e817 248 pfctlinput(PRC_REDIRECT_NET, (caddr_t)icp);
fbc81152
MK
249 } else {
250 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
251 rtredirect((struct sockaddr *)&icmpsrc,
252 (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST);
0270e817 253 pfctlinput(PRC_REDIRECT_HOST, (caddr_t)icp);
fbc81152 254 }
167351c2
MK
255 /* FALL THROUGH */
256
257 case ICMP_ECHOREPLY:
258 case ICMP_TSTAMPREPLY:
259 case ICMP_IREQREPLY:
72e4f44e
SL
260 icmpsrc.sin_addr = ip->ip_src;
261 icmpdst.sin_addr = ip->ip_dst;
262 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
263 (struct sockaddr *)&icmpdst);
fd15a680 264 return;
81a36a8d
BJ
265
266 default:
267 goto free;
268 }
269reflect:
b012ee63 270 ip->ip_len += hlen; /* since ip_input deducts this */
7b66c1fd 271 icmpstat.icps_reflect++;
06730e5a 272 icmpstat.icps_outhist[icp->icmp_type]++;
81a36a8d 273 icmp_reflect(ip);
af8f6a21 274 return;
81a36a8d
BJ
275free:
276 m_freem(dtom(ip));
277}
278
279/*
280 * Reflect the ip packet back to the source
72e4f44e 281 * TODO: rearrange ip source routing options.
81a36a8d
BJ
282 */
283icmp_reflect(ip)
284 struct ip *ip;
285{
c175a1bd
MK
286 register struct in_addr t;
287 register struct in_ifaddr *ia;
81a36a8d 288
72e4f44e 289 t = ip->ip_dst;
c175a1bd
MK
290 if (t.s_addr == INADDR_ANY)
291 t = IA_SIN(in_ifaddr)->sin_addr;
292 else for (ia = in_ifaddr; ia; ia = ia->ia_next)
293 if (t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr &&
294 (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
295 t = IA_SIN(ia)->sin_addr;
296 break;
297 }
72e4f44e
SL
298 ip->ip_dst = ip->ip_src;
299 ip->ip_src = t;
81a36a8d
BJ
300 icmp_send(ip);
301}
302
303/*
72e4f44e
SL
304 * Send an icmp packet back to the ip level,
305 * after supplying a checksum.
81a36a8d 306 */
cdad2eb1 307icmp_send(ip)
81a36a8d 308 struct ip *ip;
81a36a8d 309{
af8f6a21 310 register int hlen;
72e4f44e 311 register struct icmp *icp;
af8f6a21 312 register struct mbuf *m;
d52566dd 313
af8f6a21
SL
314 m = dtom(ip);
315 hlen = ip->ip_hl << 2;
72e4f44e
SL
316 icp = mtod(m, struct icmp *);
317 icp->icmp_cksum = 0;
318 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
319 m->m_off -= hlen;
320 m->m_len += hlen;
a60889ab 321#ifdef ICMPPRINTFS
39674d5f
SL
322 if (icmpprintfs)
323 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
a60889ab 324#endif
a1edc12b 325 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
d52566dd
BJ
326}
327
cdad2eb1 328n_time
2b4b57cd 329iptime()
d52566dd 330{
cdad2eb1 331 int s = spl6();
2752c877 332 u_long t;
d52566dd 333
b2ac7f3b 334 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
cdad2eb1
BJ
335 splx(s);
336 return (htonl(t));
d52566dd 337}