00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "dhcpd.h"
00032 #include "netinet/ip.h"
00033 #include "netinet/ip_icmp.h"
00034
00035 struct icmp_state *icmp_state;
00036 static omapi_object_type_t *dhcp_type_icmp;
00037 static int no_icmp;
00038
00039 OMAPI_OBJECT_ALLOC (icmp_state, struct icmp_state, dhcp_type_icmp)
00040
00041 #if defined (TRACING)
00042 trace_type_t *trace_icmp_input;
00043 trace_type_t *trace_icmp_output;
00044 #endif
00045
00046
00047
00048 void icmp_startup (routep, handler)
00049 int routep;
00050 void (*handler) (struct iaddr, u_int8_t *, int);
00051 {
00052 struct protoent *proto;
00053 int protocol = 1;
00054 int state;
00055 isc_result_t result;
00056
00057
00058 if (dhcp_type_icmp)
00059 log_fatal ("attempted to reinitialize icmp protocol");
00060
00061 result = omapi_object_type_register (&dhcp_type_icmp, "icmp",
00062 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00063 sizeof (struct icmp_state),
00064 0, RC_MISC);
00065
00066 if (result != ISC_R_SUCCESS)
00067 log_fatal ("Can't register icmp object type: %s",
00068 isc_result_totext (result));
00069
00070 icmp_state_allocate (&icmp_state, MDL);
00071 icmp_state -> icmp_handler = handler;
00072
00073 #if defined (TRACING)
00074 trace_icmp_input = trace_type_register ("icmp-input", (void *)0,
00075 trace_icmp_input_input,
00076 trace_icmp_input_stop, MDL);
00077 trace_icmp_output = trace_type_register ("icmp-output", (void *)0,
00078 trace_icmp_output_input,
00079 trace_icmp_output_stop, MDL);
00080
00081
00082
00083 if (!trace_playback ()) {
00084 #endif
00085
00086 proto = getprotobyname ("icmp");
00087 if (proto)
00088 protocol = proto -> p_proto;
00089
00090
00091 icmp_state -> socket = socket (AF_INET, SOCK_RAW, protocol);
00092 if (icmp_state -> socket < 0) {
00093 no_icmp = 1;
00094 log_error ("unable to create icmp socket: %m");
00095 return;
00096 }
00097
00098 #if defined (HAVE_SETFD)
00099 if (fcntl (icmp_state -> socket, F_SETFD, 1) < 0)
00100 log_error ("Can't set close-on-exec on icmp: %m");
00101 #endif
00102
00103
00104 state = 0;
00105 if (setsockopt (icmp_state -> socket, SOL_SOCKET, SO_DONTROUTE,
00106 (char *)&state, sizeof state) < 0)
00107 log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m");
00108
00109 result = (omapi_register_io_object
00110 ((omapi_object_t *)icmp_state,
00111 icmp_readsocket, 0, icmp_echoreply, 0, 0));
00112 if (result != ISC_R_SUCCESS)
00113 log_fatal ("Can't register icmp handle: %s",
00114 isc_result_totext (result));
00115 #if defined (TRACING)
00116 }
00117 #endif
00118 }
00119
00120 int icmp_readsocket (h)
00121 omapi_object_t *h;
00122 {
00123 struct icmp_state *state;
00124
00125 state = (struct icmp_state *)h;
00126 return state -> socket;
00127 }
00128
00129 int icmp_echorequest (addr)
00130 struct iaddr *addr;
00131 {
00132 struct sockaddr_in to;
00133 struct icmp icmp;
00134 int status;
00135 #if defined (TRACING)
00136 trace_iov_t iov [2];
00137 #endif
00138
00139 if (no_icmp)
00140 return 1;
00141 if (!icmp_state)
00142 log_fatal ("ICMP protocol used before initialization.");
00143
00144 memset (&to, 0, sizeof(to));
00145 #ifdef HAVE_SA_LEN
00146 to.sin_len = sizeof to;
00147 #endif
00148 to.sin_family = AF_INET;
00149 to.sin_port = 0;
00150 memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr);
00151
00152 icmp.icmp_type = ICMP_ECHO;
00153 icmp.icmp_code = 0;
00154 icmp.icmp_cksum = 0;
00155 icmp.icmp_seq = 0;
00156 #if SIZEOF_STRUCT_IADDR_P == 8
00157 icmp.icmp_id = (((u_int32_t)(u_int64_t)addr) ^
00158 (u_int32_t)(((u_int64_t)addr) >> 32));
00159 #else
00160 icmp.icmp_id = (u_int32_t)addr;
00161 #endif
00162 memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun);
00163
00164 icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp,
00165 sizeof icmp, 0));
00166
00167 #if defined (TRACING)
00168 if (trace_playback ()) {
00169 char *buf = (char *)0;
00170 unsigned buflen = 0;
00171
00172
00173 status = trace_get_packet (&trace_icmp_output, &buflen, &buf);
00174 if (status != ISC_R_SUCCESS)
00175 log_error ("icmp_echorequest: %s",
00176 isc_result_totext (status));
00177 if (buf)
00178 dfree (buf, MDL);
00179 } else {
00180 if (trace_record ()) {
00181 iov [0].buf = (char *)addr;
00182 iov [0].len = sizeof *addr;
00183 iov [1].buf = (char *)&icmp;
00184 iov [1].len = sizeof icmp;
00185 trace_write_packet_iov (trace_icmp_output,
00186 2, iov, MDL);
00187 }
00188 #endif
00189
00190 status = sendto (icmp_state -> socket,
00191 (char *)&icmp, sizeof icmp, 0,
00192 (struct sockaddr *)&to, sizeof to);
00193 if (status < 0)
00194 log_error ("icmp_echorequest %s: %m",
00195 inet_ntoa(to.sin_addr));
00196
00197 if (status != sizeof icmp)
00198 return 0;
00199 #if defined (TRACING)
00200 }
00201 #endif
00202 return 1;
00203 }
00204
00205 isc_result_t icmp_echoreply (h)
00206 omapi_object_t *h;
00207 {
00208 struct icmp *icfrom;
00209 struct ip *ip;
00210 struct sockaddr_in from;
00211 u_int8_t icbuf [1500];
00212 int status;
00213 SOCKLEN_T sl;
00214 int hlen, len;
00215 struct iaddr ia;
00216 struct icmp_state *state;
00217 #if defined (TRACING)
00218 trace_iov_t iov [2];
00219 #endif
00220
00221 state = (struct icmp_state *)h;
00222
00223 sl = sizeof from;
00224 status = recvfrom (state -> socket, (char *)icbuf, sizeof icbuf, 0,
00225 (struct sockaddr *)&from, &sl);
00226 if (status < 0) {
00227 log_error ("icmp_echoreply: %m");
00228 return ISC_R_UNEXPECTED;
00229 }
00230
00231
00232 ip = (struct ip *)icbuf;
00233 hlen = IP_HL (ip);
00234
00235
00236 if (status < hlen + (sizeof *icfrom)) {
00237 return ISC_R_SUCCESS;
00238 }
00239
00240 len = status - hlen;
00241 icfrom = (struct icmp *)(icbuf + hlen);
00242
00243
00244 if (icfrom -> icmp_type != ICMP_ECHOREPLY) {
00245 return ISC_R_SUCCESS;
00246 }
00247
00248
00249 if (state -> icmp_handler) {
00250 memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr);
00251 ia.len = sizeof from.sin_addr;
00252
00253 #if defined (TRACING)
00254 if (trace_record ()) {
00255 ia.len = htonl(ia.len);
00256 iov [0].buf = (char *)&ia;
00257 iov [0].len = sizeof ia;
00258 iov [1].buf = (char *)icbuf;
00259 iov [1].len = len;
00260 trace_write_packet_iov (trace_icmp_input, 2, iov, MDL);
00261 ia.len = ntohl(ia.len);
00262 }
00263 #endif
00264 (*state -> icmp_handler) (ia, icbuf, len);
00265 }
00266 return ISC_R_SUCCESS;
00267 }
00268
00269 #if defined (TRACING)
00270 void trace_icmp_input_input (trace_type_t *ttype, unsigned length, char *buf)
00271 {
00272 struct iaddr *ia;
00273 u_int8_t *icbuf;
00274 ia = (struct iaddr *)buf;
00275 ia->len = ntohl(ia->len);
00276 icbuf = (u_int8_t *)(ia + 1);
00277 if (icmp_state -> icmp_handler)
00278 (*icmp_state -> icmp_handler) (*ia, icbuf,
00279 (int)(length - sizeof ia));
00280 }
00281
00282 void trace_icmp_input_stop (trace_type_t *ttype) { }
00283
00284 void trace_icmp_output_input (trace_type_t *ttype, unsigned length, char *buf)
00285 {
00286 struct iaddr ia;
00287
00288 if (length != (sizeof (struct icmp) + sizeof (ia))) {
00289 log_error ("trace_icmp_output_input: data size mismatch %d:%d",
00290 length, (int)(sizeof (struct icmp) + sizeof (ia)));
00291 return;
00292 }
00293 ia.len = 4;
00294 memcpy (ia.iabuf, buf, 4);
00295
00296 log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia));
00297 }
00298
00299 void trace_icmp_output_stop (trace_type_t *ttype) { }
00300 #endif