]>
git.ipfire.org Git - thirdparty/dhcp.git/blob - common/icmp.c
cdf92a377c3d35b0173d08f9429f4c948b6b3cee
3 ICMP Protocol engine - for sending out pings and receiving
7 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * This Source Code Form is subject to the terms of the Mozilla Public
11 * License, v. 2.0. If a copy of the MPL was not distributed with this
12 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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 * Newmarket, NH 03857 USA
26 * https://www.isc.org/
31 #include "netinet/ip.h"
32 #include "netinet/ip_icmp.h"
34 struct icmp_state
*icmp_state
;
35 static omapi_object_type_t
*dhcp_type_icmp
;
38 OMAPI_OBJECT_ALLOC (icmp_state
, struct icmp_state
, dhcp_type_icmp
)
41 trace_type_t
*trace_icmp_input
;
42 trace_type_t
*trace_icmp_output
;
45 /* Initialize the ICMP protocol. */
47 void icmp_startup (routep
, handler
)
49 void (*handler
) (struct iaddr
, u_int8_t
*, int);
51 struct protoent
*proto
;
56 /* Only initialize icmp once. */
58 log_fatal ("attempted to reinitialize icmp protocol");
60 result
= omapi_object_type_register (&dhcp_type_icmp
, "icmp",
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 sizeof (struct icmp_state
),
65 if (result
!= ISC_R_SUCCESS
)
66 log_fatal ("Can't register icmp object type: %s",
67 isc_result_totext (result
));
69 icmp_state_allocate (&icmp_state
, MDL
);
70 icmp_state
-> icmp_handler
= handler
;
73 trace_icmp_input
= trace_type_register ("icmp-input", (void *)0,
74 trace_icmp_input_input
,
75 trace_icmp_input_stop
, MDL
);
76 trace_icmp_output
= trace_type_register ("icmp-output", (void *)0,
77 trace_icmp_output_input
,
78 trace_icmp_output_stop
, MDL
);
80 /* If we're playing back a trace file, don't create the socket
81 or set up the callback. */
82 if (!trace_playback ()) {
84 /* Get the protocol number (should be 1). */
85 proto
= getprotobyname ("icmp");
87 protocol
= proto
-> p_proto
;
89 /* Get a raw socket for the ICMP protocol. */
90 icmp_state
-> socket
= socket (AF_INET
, SOCK_RAW
, protocol
);
91 if (icmp_state
-> socket
< 0) {
93 log_error ("unable to create icmp socket: %m");
97 #if defined (HAVE_SETFD)
98 if (fcntl (icmp_state
-> socket
, F_SETFD
, 1) < 0)
99 log_error ("Can't set close-on-exec on icmp: %m");
102 /* Make sure it does routing... */
104 if (setsockopt (icmp_state
-> socket
, SOL_SOCKET
, SO_DONTROUTE
,
105 (char *)&state
, sizeof state
) < 0)
106 log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m");
108 result
= (omapi_register_io_object
109 ((omapi_object_t
*)icmp_state
,
110 icmp_readsocket
, 0, icmp_echoreply
, 0, 0));
111 if (result
!= ISC_R_SUCCESS
)
112 log_fatal ("Can't register icmp handle: %s",
113 isc_result_totext (result
));
114 #if defined (TRACING)
119 int icmp_readsocket (h
)
122 struct icmp_state
*state
;
124 state
= (struct icmp_state
*)h
;
125 return state
-> socket
;
128 int icmp_echorequest (addr
)
131 struct sockaddr_in to
;
134 #if defined (TRACING)
141 log_fatal ("ICMP protocol used before initialization.");
143 memset (&to
, 0, sizeof(to
));
145 to
.sin_len
= sizeof to
;
147 to
.sin_family
= AF_INET
;
148 to
.sin_port
= 0; /* unused. */
149 memcpy (&to
.sin_addr
, addr
-> iabuf
, sizeof to
.sin_addr
); /* XXX */
151 icmp
.icmp_type
= ICMP_ECHO
;
155 #if SIZEOF_STRUCT_IADDR_P == 8
156 icmp
.icmp_id
= (((u_int32_t
)(u_int64_t
)addr
) ^
157 (u_int32_t
)(((u_int64_t
)addr
) >> 32));
159 icmp
.icmp_id
= (u_int32_t
)addr
;
161 memset (&icmp
.icmp_dun
, 0, sizeof icmp
.icmp_dun
);
163 icmp
.icmp_cksum
= wrapsum (checksum ((unsigned char *)&icmp
,
166 #if defined (TRACING)
167 if (trace_playback ()) {
168 char *buf
= (char *)0;
171 /* Consume the ICMP event. */
172 status
= trace_get_packet (&trace_icmp_output
, &buflen
, &buf
);
173 if (status
!= ISC_R_SUCCESS
)
174 log_error ("icmp_echorequest: %s",
175 isc_result_totext (status
));
179 if (trace_record ()) {
180 iov
[0].buf
= (char *)addr
;
181 iov
[0].len
= sizeof *addr
;
182 iov
[1].buf
= (char *)&icmp
;
183 iov
[1].len
= sizeof icmp
;
184 trace_write_packet_iov (trace_icmp_output
,
188 /* Send the ICMP packet... */
189 status
= sendto (icmp_state
-> socket
,
190 (char *)&icmp
, sizeof icmp
, 0,
191 (struct sockaddr
*)&to
, sizeof to
);
193 log_error ("icmp_echorequest %s: %m",
194 inet_ntoa(to
.sin_addr
));
196 if (status
!= sizeof icmp
)
198 #if defined (TRACING)
204 isc_result_t
icmp_echoreply (h
)
209 struct sockaddr_in from
;
210 u_int8_t icbuf
[1500];
215 struct icmp_state
*state
;
216 #if defined (TRACING)
220 state
= (struct icmp_state
*)h
;
223 status
= recvfrom (state
-> socket
, (char *)icbuf
, sizeof icbuf
, 0,
224 (struct sockaddr
*)&from
, &sl
);
226 log_error ("icmp_echoreply: %m");
227 return ISC_R_UNEXPECTED
;
230 /* Find the IP header length... */
231 ip
= (struct ip
*)icbuf
;
235 if (status
< hlen
+ (sizeof *icfrom
)) {
236 return ISC_R_SUCCESS
;
240 icfrom
= (struct icmp
*)(icbuf
+ hlen
);
242 /* Silently discard ICMP packets that aren't echoreplies. */
243 if (icfrom
-> icmp_type
!= ICMP_ECHOREPLY
) {
244 return ISC_R_SUCCESS
;
247 /* If we were given a second-stage handler, call it. */
248 if (state
-> icmp_handler
) {
249 memcpy (ia
.iabuf
, &from
.sin_addr
, sizeof from
.sin_addr
);
250 ia
.len
= sizeof from
.sin_addr
;
252 #if defined (TRACING)
253 if (trace_record ()) {
254 ia
.len
= htonl(ia
.len
);
255 iov
[0].buf
= (char *)&ia
;
256 iov
[0].len
= sizeof ia
;
257 iov
[1].buf
= (char *)icbuf
;
259 trace_write_packet_iov (trace_icmp_input
, 2, iov
, MDL
);
260 ia
.len
= ntohl(ia
.len
);
263 (*state
-> icmp_handler
) (ia
, icbuf
, len
);
265 return ISC_R_SUCCESS
;
268 #if defined (TRACING)
269 void trace_icmp_input_input (trace_type_t
*ttype
, unsigned length
, char *buf
)
273 ia
= (struct iaddr
*)buf
;
274 ia
->len
= ntohl(ia
->len
);
275 icbuf
= (u_int8_t
*)(ia
+ 1);
276 if (icmp_state
-> icmp_handler
)
277 (*icmp_state
-> icmp_handler
) (*ia
, icbuf
,
278 (int)(length
- sizeof ia
));
281 void trace_icmp_input_stop (trace_type_t
*ttype
) { }
283 void trace_icmp_output_input (trace_type_t
*ttype
, unsigned length
, char *buf
)
287 if (length
!= (sizeof (struct icmp
) + sizeof (ia
))) {
288 log_error ("trace_icmp_output_input: data size mismatch %d:%d",
289 length
, (int)(sizeof (struct icmp
) + sizeof (ia
)));
293 memcpy (ia
.iabuf
, buf
, 4);
295 log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia
));
298 void trace_icmp_output_stop (trace_type_t
*ttype
) { }