3 ICMP Protocol engine - for sending out pings and receiving
7 * Copyright (c) 1996-1999 Internet Software Consortium.
8 * Use is subject to license terms which appear in the file named
9 * ISC-LICENSE that should have accompanied this file when you
10 * received it. If a file named ISC-LICENSE did not accompany this
11 * file, or you are not sure the one you have is correct, you may
12 * obtain an applicable copy of the license at:
14 * http://www.isc.org/isc-license-1.0.html.
16 * This file is part of the ISC DHCP distribution. The documentation
17 * associated with this file is listed in the file DOCUMENTATION,
18 * included in the top-level directory of this release.
20 * Support and other services are available for ISC products - see
21 * http://www.isc.org for more information.
25 static char copyright
[] =
26 "$Id: icmp.c,v 1.13 1999/03/16 05:50:34 mellon Exp $ Copyright (c) 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
30 #include "netinet/ip.h"
31 #include "netinet/ip_icmp.h"
33 static int icmp_protocol_initialized
;
34 static int icmp_protocol_fd
;
36 /* Initialize the ICMP protocol. */
38 void icmp_startup (routep
, handler
)
40 void (*handler
) PROTO ((struct iaddr
, u_int8_t
*, int));
42 struct protoent
*proto
;
44 struct sockaddr_in from
;
48 /* Only initialize icmp once. */
49 if (icmp_protocol_initialized
)
50 log_fatal ("attempted to reinitialize icmp protocol");
51 icmp_protocol_initialized
= 1;
53 /* Get the protocol number (should be 1). */
54 proto
= getprotobyname ("icmp");
56 protocol
= proto
-> p_proto
;
58 /* Get a raw socket for the ICMP protocol. */
59 icmp_protocol_fd
= socket (AF_INET
, SOCK_RAW
, protocol
);
60 if (icmp_protocol_fd
< 0)
61 log_fatal ("unable to create icmp socket: %m");
63 /* Make sure it does routing... */
65 if (setsockopt (icmp_protocol_fd
, SOL_SOCKET
, SO_DONTROUTE
,
66 (char *)&state
, sizeof state
) < 0)
67 log_fatal ("Unable to disable SO_DONTROUTE on ICMP socket: %m");
69 add_protocol ("icmp", icmp_protocol_fd
,
70 icmp_echoreply
, (void *)handler
);
73 int icmp_echorequest (addr
)
76 struct sockaddr_in to
;
80 if (!icmp_protocol_initialized
)
81 log_fatal ("attempt to use ICMP protocol before initialization.");
84 to
.sin_len
= sizeof to
;
86 to
.sin_family
= AF_INET
;
87 to
.sin_port
= 0; /* unused. */
88 memcpy (&to
.sin_addr
, addr
-> iabuf
, sizeof to
.sin_addr
); /* XXX */
90 icmp
.icmp_type
= ICMP_ECHO
;
95 icmp
.icmp_id
= (((u_int32_t
)(u_int64_t
)addr
) ^
96 (u_int32_t
)(((u_int64_t
)addr
) >> 32));
98 icmp
.icmp_id
= (u_int32_t
)addr
;
100 memset (&icmp
.icmp_dun
, 0, sizeof icmp
.icmp_dun
);
102 icmp
.icmp_cksum
= wrapsum (checksum ((unsigned char *)&icmp
,
105 /* Send the ICMP packet... */
106 status
= sendto (icmp_protocol_fd
, (char *)&icmp
, sizeof icmp
, 0,
107 (struct sockaddr
*)&to
, sizeof to
);
109 log_error ("icmp_echorequest %s: %m", inet_ntoa(to
.sin_addr
));
111 if (status
!= sizeof icmp
)
116 void icmp_echoreply (protocol
)
117 struct protocol
*protocol
;
121 struct sockaddr_in from
;
122 unsigned char icbuf
[1500];
126 void (*handler
) PROTO ((struct iaddr
, u_int8_t
*, int));
129 status
= recvfrom (protocol
-> fd
, (char *)icbuf
, sizeof icbuf
, 0,
130 (struct sockaddr
*)&from
, &len
);
132 log_error ("icmp_echoreply: %m");
136 /* Find the IP header length... */
137 ip
= (struct ip
*)icbuf
;
138 hlen
= ip
-> ip_hl
<< 2;
141 if (status
< hlen
+ (sizeof *icfrom
)) {
146 icfrom
= (struct icmp
*)(icbuf
+ hlen
);
148 /* Silently discard ICMP packets that aren't echoreplies. */
149 if (icfrom
-> icmp_type
!= ICMP_ECHOREPLY
) {
153 /* If we were given a second-stage handler, call it. */
154 if (protocol
-> local
) {
155 handler
= ((void (*) PROTO ((struct iaddr
, u_int8_t
*, int)))
157 memcpy (ia
.iabuf
, &from
.sin_addr
, sizeof from
.sin_addr
);
158 ia
.len
= sizeof from
.sin_addr
;
160 (*handler
) (ia
, icbuf
, len
);