ISC DHCP  4.3.0
A reference DHCPv4 and DHCPv6 implementation
icmp.c
Go to the documentation of this file.
1 /* dhcp.c
2 
3  ICMP Protocol engine - for sending out pings and receiving
4  responses. */
5 
6 /*
7  * Copyright (c) 2011,2013,2014 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1996-2003 by Internet Software Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Internet Systems Consortium, Inc.
24  * 950 Charter Street
25  * Redwood City, CA 94063
26  * <info@isc.org>
27  * https://www.isc.org/
28  *
29  */
30 
31 #include "dhcpd.h"
32 #include "netinet/ip.h"
33 #include "netinet/ip_icmp.h"
34 
36 static omapi_object_type_t *dhcp_type_icmp;
37 static int no_icmp;
38 
39 OMAPI_OBJECT_ALLOC (icmp_state, struct icmp_state, dhcp_type_icmp)
40 
41 #if defined (TRACING)
42 trace_type_t *trace_icmp_input;
43 trace_type_t *trace_icmp_output;
44 #endif
45 
46 /* Initialize the ICMP protocol. */
47 
48 void icmp_startup (routep, handler)
49  int routep;
50  void (*handler) (struct iaddr, u_int8_t *, int);
51 {
52  struct protoent *proto;
53  int protocol = 1;
54  int state;
55  isc_result_t result;
56 
57  /* Only initialize icmp once. */
58  if (dhcp_type_icmp)
59  log_fatal ("attempted to reinitialize icmp protocol");
60 
61  result = omapi_object_type_register (&dhcp_type_icmp, "icmp",
62  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63  sizeof (struct icmp_state),
64  0, RC_MISC);
65 
66  if (result != ISC_R_SUCCESS)
67  log_fatal ("Can't register icmp object type: %s",
68  isc_result_totext (result));
69 
70  icmp_state_allocate (&icmp_state, MDL);
71  icmp_state -> icmp_handler = handler;
72 
73 #if defined (TRACING)
74  trace_icmp_input = trace_type_register ("icmp-input", (void *)0,
77  trace_icmp_output = trace_type_register ("icmp-output", (void *)0,
80 
81  /* If we're playing back a trace file, don't create the socket
82  or set up the callback. */
83  if (!trace_playback ()) {
84 #endif
85  /* Get the protocol number (should be 1). */
86  proto = getprotobyname ("icmp");
87  if (proto)
88  protocol = proto -> p_proto;
89 
90  /* Get a raw socket for the ICMP protocol. */
91  icmp_state -> socket = socket (AF_INET, SOCK_RAW, protocol);
92  if (icmp_state -> socket < 0) {
93  no_icmp = 1;
94  log_error ("unable to create icmp socket: %m");
95  return;
96  }
97 
98 #if defined (HAVE_SETFD)
99  if (fcntl (icmp_state -> socket, F_SETFD, 1) < 0)
100  log_error ("Can't set close-on-exec on icmp: %m");
101 #endif
102 
103  /* Make sure it does routing... */
104  state = 0;
105  if (setsockopt (icmp_state -> socket, SOL_SOCKET, SO_DONTROUTE,
106  (char *)&state, sizeof state) < 0)
107  log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m");
108 
109  result = (omapi_register_io_object
110  ((omapi_object_t *)icmp_state,
111  icmp_readsocket, 0, icmp_echoreply, 0, 0));
112  if (result != ISC_R_SUCCESS)
113  log_fatal ("Can't register icmp handle: %s",
114  isc_result_totext (result));
115 #if defined (TRACING)
116  }
117 #endif
118 }
119 
121  omapi_object_t *h;
122 {
123  struct icmp_state *state;
124 
125  state = (struct icmp_state *)h;
126  return state -> socket;
127 }
128 
130  struct iaddr *addr;
131 {
132  struct sockaddr_in to;
133  struct icmp icmp;
134  int status;
135 #if defined (TRACING)
136  trace_iov_t iov [2];
137 #endif
138 
139  if (no_icmp)
140  return 1;
141  if (!icmp_state)
142  log_fatal ("ICMP protocol used before initialization.");
143 
144  memset (&to, 0, sizeof(to));
145 #ifdef HAVE_SA_LEN
146  to.sin_len = sizeof to;
147 #endif
148  to.sin_family = AF_INET;
149  to.sin_port = 0; /* unused. */
150  memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr); /* XXX */
151 
152  icmp.icmp_type = ICMP_ECHO;
153  icmp.icmp_code = 0;
154  icmp.icmp_cksum = 0;
155  icmp.icmp_seq = 0;
156 #if SIZEOF_STRUCT_IADDR_P == 8
157  icmp.icmp_id = (((u_int32_t)(u_int64_t)addr) ^
158  (u_int32_t)(((u_int64_t)addr) >> 32));
159 #else
160  icmp.icmp_id = (u_int32_t)addr;
161 #endif
162  memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun);
163 
164  icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp,
165  sizeof icmp, 0));
166 
167 #if defined (TRACING)
168  if (trace_playback ()) {
169  char *buf = (char *)0;
170  unsigned buflen = 0;
171 
172  /* Consume the ICMP event. */
173  status = trace_get_packet (&trace_icmp_output, &buflen, &buf);
174  if (status != ISC_R_SUCCESS)
175  log_error ("icmp_echorequest: %s",
176  isc_result_totext (status));
177  if (buf)
178  dfree (buf, MDL);
179  } else {
180  if (trace_record ()) {
181  iov [0].buf = (char *)addr;
182  iov [0].len = sizeof *addr;
183  iov [1].buf = (char *)&icmp;
184  iov [1].len = sizeof icmp;
185  trace_write_packet_iov (trace_icmp_output,
186  2, iov, MDL);
187  }
188 #endif
189  /* Send the ICMP packet... */
190  status = sendto (icmp_state -> socket,
191  (char *)&icmp, sizeof icmp, 0,
192  (struct sockaddr *)&to, sizeof to);
193  if (status < 0)
194  log_error ("icmp_echorequest %s: %m",
195  inet_ntoa(to.sin_addr));
196 
197  if (status != sizeof icmp)
198  return 0;
199 #if defined (TRACING)
200  }
201 #endif
202  return 1;
203 }
204 
205 isc_result_t icmp_echoreply (h)
206  omapi_object_t *h;
207 {
208  struct icmp *icfrom;
209  struct ip *ip;
210  struct sockaddr_in from;
211  u_int8_t icbuf [1500];
212  int status;
213  SOCKLEN_T sl;
214  int hlen, len;
215  struct iaddr ia;
216  struct icmp_state *state;
217 #if defined (TRACING)
218  trace_iov_t iov [2];
219 #endif
220 
221  state = (struct icmp_state *)h;
222 
223  sl = sizeof from;
224  status = recvfrom (state -> socket, (char *)icbuf, sizeof icbuf, 0,
225  (struct sockaddr *)&from, &sl);
226  if (status < 0) {
227  log_error ("icmp_echoreply: %m");
228  return ISC_R_UNEXPECTED;
229  }
230 
231  /* Find the IP header length... */
232  ip = (struct ip *)icbuf;
233  hlen = IP_HL (ip);
234 
235  /* Short packet? */
236  if (status < hlen + (sizeof *icfrom)) {
237  return ISC_R_SUCCESS;
238  }
239 
240  len = status - hlen;
241  icfrom = (struct icmp *)(icbuf + hlen);
242 
243  /* Silently discard ICMP packets that aren't echoreplies. */
244  if (icfrom -> icmp_type != ICMP_ECHOREPLY) {
245  return ISC_R_SUCCESS;
246  }
247 
248  /* If we were given a second-stage handler, call it. */
249  if (state -> icmp_handler) {
250  memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr);
251  ia.len = sizeof from.sin_addr;
252 
253 #if defined (TRACING)
254  if (trace_record ()) {
255  ia.len = htonl(ia.len);
256  iov [0].buf = (char *)&ia;
257  iov [0].len = sizeof ia;
258  iov [1].buf = (char *)icbuf;
259  iov [1].len = len;
260  trace_write_packet_iov (trace_icmp_input, 2, iov, MDL);
261  ia.len = ntohl(ia.len);
262  }
263 #endif
264  (*state -> icmp_handler) (ia, icbuf, len);
265  }
266  return ISC_R_SUCCESS;
267 }
268 
269 #if defined (TRACING)
270 void trace_icmp_input_input (trace_type_t *ttype, unsigned length, char *buf)
271 {
272  struct iaddr *ia;
273  u_int8_t *icbuf;
274  ia = (struct iaddr *)buf;
275  ia->len = ntohl(ia->len);
276  icbuf = (u_int8_t *)(ia + 1);
277  if (icmp_state -> icmp_handler)
278  (*icmp_state -> icmp_handler) (*ia, icbuf,
279  (int)(length - sizeof ia));
280 }
281 
282 void trace_icmp_input_stop (trace_type_t *ttype) { }
283 
284 void trace_icmp_output_input (trace_type_t *ttype, unsigned length, char *buf)
285 {
286  struct iaddr ia;
287 
288  if (length != (sizeof (struct icmp) + sizeof (ia))) {
289  log_error ("trace_icmp_output_input: data size mismatch %d:%d",
290  length, (int)(sizeof (struct icmp) + sizeof (ia)));
291  return;
292  }
293  ia.len = 4;
294  memcpy (ia.iabuf, buf, 4);
295 
296  log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia));
297 }
298 
299 void trace_icmp_output_stop (trace_type_t *ttype) { }
300 #endif /* TRACING */
const char * buf
Definition: trace.h:75
int trace_playback(void)
isc_result_t omapi_register_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition: dispatch.c:199
u_int8_t icmp_code
Definition: ip_icmp.h:53
const char * piaddr(const struct iaddr addr)
Definition: inet.c:581
void trace_icmp_output_input(trace_type_t *, unsigned, char *)
#define MDL
Definition: omapip.h:568
unsigned char iabuf[16]
Definition: inet.h:33
void icmp_startup(int routep, void *handler)
Definition: icmp.c:48
void trace_icmp_input_stop(trace_type_t *)
#define ICMP_ECHOREPLY
Definition: ip_icmp.h:126
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
void trace_icmp_input_input(trace_type_t *, unsigned, char *)
int log_error(const char *,...) __attribute__((__format__(__printf__
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
unsigned len
Definition: inet.h:32
#define OMAPI_OBJECT_ALLOC(name, stype, type)
Definition: omapip.h:161
struct icmp_state * icmp_state
Definition: icmp.c:35
u_int32_t wrapsum(u_int32_t sum)
Definition: packet.c:84
#define IP_HL(iph)
Definition: ip.h:63
void log_fatal(const char *,...) __attribute__((__format__(__printf__
void trace_icmp_output_stop(trace_type_t *)
u_int16_t icmp_cksum
Definition: ip_icmp.h:54
Definition: ip_icmp.h:51
unsigned len
Definition: trace.h:76
int socket
Definition: dhcpd.h:1392
Definition: ip.h:47
int trace_record(void)
void dfree(void *, const char *, int)
Definition: alloc.c:131
Definition: inet.h:31
isc_result_t omapi_object_type_register(omapi_object_type_t **, const char *, isc_result_t(*)(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *), isc_result_t(*)(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **), isc_result_t(*)(omapi_object_t *, const char *, int), isc_result_t(*)(omapi_object_t *, const char *, va_list), isc_result_t(*)(omapi_object_t *, omapi_object_t *, omapi_object_t *), isc_result_t(*)(omapi_object_t **, omapi_object_t *, omapi_object_t *), isc_result_t(*)(omapi_object_t **, omapi_object_t *), isc_result_t(*)(omapi_object_t *, omapi_object_t *), isc_result_t(*)(omapi_object_t *, const char *, int), isc_result_t(*)(omapi_object_t **, const char *, int), isc_result_t(*)(size_t), size_t, isc_result_t(*)(omapi_object_t *, const char *, int), int)
Definition: support.c:194
isc_result_t trace_get_packet(trace_type_t **, unsigned *, char **)
const char int
Definition: omapip.h:443
u_int8_t icmp_type
Definition: ip_icmp.h:52
int icmp_readsocket(omapi_object_t *h)
Definition: icmp.c:120
isc_result_t icmp_echoreply(omapi_object_t *h)
Definition: icmp.c:205
#define ICMP_ECHO
Definition: ip_icmp.h:147
int icmp_echorequest(struct iaddr *addr)
Definition: icmp.c:129
#define SOCKLEN_T
Definition: osdep.h:281
#define RC_MISC
Definition: alloc.h:56
u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
Definition: packet.c:45
union icmp::@2 icmp_dun