3 ICMP Protocol engine - for sending out pings and receiving
7 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
28 * This software has been written for Internet Systems Consortium
29 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30 * To learn more about Internet Systems Consortium, see
31 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
32 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
37 static char copyright
[] =
38 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
42 #include "netinet/ip.h"
43 #include "netinet/ip_icmp.h"
45 struct icmp_state
*icmp_state
;
46 static omapi_object_type_t
*dhcp_type_icmp
;
49 OMAPI_OBJECT_ALLOC (icmp_state
, struct icmp_state
, dhcp_type_icmp
)
52 trace_type_t
*trace_icmp_input
;
53 trace_type_t
*trace_icmp_output
;
56 /* Initialize the ICMP protocol. */
58 void icmp_startup (routep
, handler
)
60 void (*handler
) PROTO ((struct iaddr
, u_int8_t
*, int));
62 struct protoent
*proto
;
64 // struct sockaddr_in from;
67 // struct icmp_state *new;
71 /* Only initialize icmp once. */
73 log_fatal ("attempted to reinitialize icmp protocol");
75 result
= omapi_object_type_register (&dhcp_type_icmp
, "icmp",
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 sizeof (struct icmp_state
),
80 if (result
!= ISC_R_SUCCESS
)
81 log_fatal ("Can't register icmp object type: %s",
82 isc_result_totext (result
));
84 icmp_state_allocate (&icmp_state
, MDL
);
85 icmp_state
-> icmp_handler
= handler
;
88 trace_icmp_input
= trace_type_register ("icmp-input", (void *)0,
89 trace_icmp_input_input
,
90 trace_icmp_input_stop
, MDL
);
91 trace_icmp_output
= trace_type_register ("icmp-output", (void *)0,
92 trace_icmp_output_input
,
93 trace_icmp_output_stop
, MDL
);
95 /* If we're playing back a trace file, don't create the socket
96 or set up the callback. */
97 if (!trace_playback ()) {
99 /* Get the protocol number (should be 1). */
100 proto
= getprotobyname ("icmp");
102 protocol
= proto
-> p_proto
;
104 /* Get a raw socket for the ICMP protocol. */
105 icmp_state
-> socket
= socket (AF_INET
, SOCK_RAW
, protocol
);
106 if (icmp_state
-> socket
< 0) {
108 log_error ("unable to create icmp socket: %m");
112 #if defined (HAVE_SETFD)
113 if (fcntl (icmp_state
-> socket
, F_SETFD
, 1) < 0)
114 log_error ("Can't set close-on-exec on icmp: %m");
117 /* Make sure it does routing... */
119 if (setsockopt (icmp_state
-> socket
, SOL_SOCKET
, SO_DONTROUTE
,
120 (char *)&state
, sizeof state
) < 0)
121 log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m");
123 result
= (omapi_register_io_object
124 ((omapi_object_t
*)icmp_state
,
125 icmp_readsocket
, 0, icmp_echoreply
, 0, 0));
126 if (result
!= ISC_R_SUCCESS
)
127 log_fatal ("Can't register icmp handle: %s",
128 isc_result_totext (result
));
129 #if defined (TRACING)
134 int icmp_readsocket (h
)
137 struct icmp_state
*state
;
139 state
= (struct icmp_state
*)h
;
140 return state
-> socket
;
143 int icmp_echorequest (addr
)
146 struct sockaddr_in to
;
149 #if defined (TRACING)
156 log_fatal ("ICMP protocol used before initialization.");
158 memset (&to
, 0, sizeof(to
));
160 to
.sin_len
= sizeof to
;
162 to
.sin_family
= AF_INET
;
163 to
.sin_port
= 0; /* unused. */
164 memcpy (&to
.sin_addr
, addr
-> iabuf
, sizeof to
.sin_addr
); /* XXX */
166 icmp
.icmp_type
= ICMP_ECHO
;
171 icmp
.icmp_id
= (((u_int32_t
)(u_int64_t
)addr
) ^
172 (u_int32_t
)(((u_int64_t
)addr
) >> 32));
174 icmp
.icmp_id
= (u_int32_t
)addr
;
176 memset (&icmp
.icmp_dun
, 0, sizeof icmp
.icmp_dun
);
178 icmp
.icmp_cksum
= wrapsum (checksum ((unsigned char *)&icmp
,
181 #if defined (TRACING)
182 if (trace_playback ()) {
183 char *buf
= (char *)0;
186 /* Consume the ICMP event. */
187 status
= trace_get_packet (&trace_icmp_output
, &buflen
, &buf
);
188 if (status
!= ISC_R_SUCCESS
)
189 log_error ("icmp_echorequest: %s",
190 isc_result_totext (status
));
194 if (trace_record ()) {
195 iov
[0].buf
= (char *)addr
;
196 iov
[0].len
= sizeof *addr
;
197 iov
[1].buf
= (char *)&icmp
;
198 iov
[1].len
= sizeof icmp
;
199 trace_write_packet_iov (trace_icmp_output
,
203 /* Send the ICMP packet... */
204 status
= sendto (icmp_state
-> socket
,
205 (char *)&icmp
, sizeof icmp
, 0,
206 (struct sockaddr
*)&to
, sizeof to
);
208 log_error ("icmp_echorequest %s: %m",
209 inet_ntoa(to
.sin_addr
));
211 if (status
!= sizeof icmp
)
213 #if defined (TRACING)
219 isc_result_t
icmp_echoreply (h
)
224 struct sockaddr_in from
;
225 u_int8_t icbuf
[1500];
230 struct icmp_state
*state
;
231 #if defined (TRACING)
235 state
= (struct icmp_state
*)h
;
238 status
= recvfrom (state
-> socket
, (char *)icbuf
, sizeof icbuf
, 0,
239 (struct sockaddr
*)&from
, &sl
);
241 log_error ("icmp_echoreply: %m");
242 return ISC_R_UNEXPECTED
;
245 /* Find the IP header length... */
246 ip
= (struct ip
*)icbuf
;
250 if (status
< hlen
+ (sizeof *icfrom
)) {
251 return ISC_R_SUCCESS
;
255 icfrom
= (struct icmp
*)(icbuf
+ hlen
);
257 /* Silently discard ICMP packets that aren't echoreplies. */
258 if (icfrom
-> icmp_type
!= ICMP_ECHOREPLY
) {
259 return ISC_R_SUCCESS
;
262 /* If we were given a second-stage handler, call it. */
263 if (state
-> icmp_handler
) {
264 memcpy (ia
.iabuf
, &from
.sin_addr
, sizeof from
.sin_addr
);
265 ia
.len
= sizeof from
.sin_addr
;
267 #if defined (TRACING)
268 if (trace_record ()) {
269 ia
.len
= htonl(ia
.len
);
270 iov
[0].buf
= (char *)&ia
;
271 iov
[0].len
= sizeof ia
;
272 iov
[1].buf
= (char *)icbuf
;
274 trace_write_packet_iov (trace_icmp_input
, 2, iov
, MDL
);
275 ia
.len
= ntohl(ia
.len
);
278 (*state
-> icmp_handler
) (ia
, icbuf
, len
);
280 return ISC_R_SUCCESS
;
283 #if defined (TRACING)
284 void trace_icmp_input_input (trace_type_t
*ttype
, unsigned length
, char *buf
)
289 ia
= (struct iaddr
*)buf
;
290 ia
->len
= ntohl(ia
->len
);
291 icbuf
= (u_int8_t
*)(ia
+ 1);
292 if (icmp_state
-> icmp_handler
)
293 (*icmp_state
-> icmp_handler
) (*ia
, icbuf
,
294 (int)(length
- sizeof ia
));
297 void trace_icmp_input_stop (trace_type_t
*ttype
) { }
299 void trace_icmp_output_input (trace_type_t
*ttype
, unsigned length
, char *buf
)
304 if (length
!= (sizeof (*icmp
) + (sizeof ia
))) {
305 log_error ("trace_icmp_output_input: data size mismatch %d:%d",
306 length
, (int)((sizeof (*icmp
)) + (sizeof ia
)));
310 memcpy (ia
.iabuf
, buf
, 4);
311 icmp
= (struct icmp
*)(buf
+ 1);
313 log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia
));
316 void trace_icmp_output_stop (trace_type_t
*ttype
) { }