ISC DHCP  4.4.1
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) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 1996-2003 by Internet Software Consortium
9  *
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/.
13  *
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.
21  *
22  * Internet Systems Consortium, Inc.
23  * 950 Charter Street
24  * Redwood City, CA 94063
25  * <info@isc.org>
26  * https://www.isc.org/
27  *
28  */
29 
30 #include "dhcpd.h"
31 #include "netinet/ip.h"
32 #include "netinet/ip_icmp.h"
33 
35 static omapi_object_type_t *dhcp_type_icmp;
36 static int no_icmp;
37 
38 OMAPI_OBJECT_ALLOC (icmp_state, struct icmp_state, dhcp_type_icmp)
39 
40 #if defined (TRACING)
41 trace_type_t *trace_icmp_input;
42 trace_type_t *trace_icmp_output;
43 #endif
44 
45 /* Initialize the ICMP protocol. */
46 
47 void icmp_startup (routep, handler)
48  int routep;
49  void (*handler) (struct iaddr, u_int8_t *, int);
50 {
51  struct protoent *proto;
52  int protocol = 1;
53  int state;
54  isc_result_t result;
55 
56  /* Only initialize icmp once. */
57  if (dhcp_type_icmp)
58  log_fatal ("attempted to reinitialize icmp protocol");
59 
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),
63  0, RC_MISC);
64 
65  if (result != ISC_R_SUCCESS)
66  log_fatal ("Can't register icmp object type: %s",
67  isc_result_totext (result));
68 
69  icmp_state_allocate (&icmp_state, MDL);
70  icmp_state -> icmp_handler = handler;
71 
72 #if defined (TRACING)
73  trace_icmp_input = trace_type_register ("icmp-input", (void *)0,
76  trace_icmp_output = trace_type_register ("icmp-output", (void *)0,
79 
80  /* If we're playing back a trace file, don't create the socket
81  or set up the callback. */
82  if (!trace_playback ()) {
83 #endif
84  /* Get the protocol number (should be 1). */
85  proto = getprotobyname ("icmp");
86  if (proto)
87  protocol = proto -> p_proto;
88 
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) {
92  no_icmp = 1;
93  log_error ("unable to create icmp socket: %m");
94  return;
95  }
96 
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");
100 #endif
101 
102  /* Make sure it does routing... */
103  state = 0;
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");
107 
108  result = (omapi_register_io_object
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)
115  }
116 #endif
117 }
118 
120  omapi_object_t *h;
121 {
122  struct icmp_state *state;
123 
124  state = (struct icmp_state *)h;
125  return state -> socket;
126 }
127 
129  struct iaddr *addr;
130 {
131  struct sockaddr_in to;
132  struct icmp icmp;
133  int status;
134 #if defined (TRACING)
135  trace_iov_t iov [2];
136 #endif
137 
138  if (no_icmp)
139  return 1;
140  if (!icmp_state)
141  log_fatal ("ICMP protocol used before initialization.");
142 
143  memset (&to, 0, sizeof(to));
144 #ifdef HAVE_SA_LEN
145  to.sin_len = sizeof to;
146 #endif
147  to.sin_family = AF_INET;
148  to.sin_port = 0; /* unused. */
149  memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr); /* XXX */
150 
152  icmp.icmp_code = 0;
153  icmp.icmp_cksum = 0;
154  icmp.icmp_seq = 0;
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));
158 #else
159  icmp.icmp_id = (u_int32_t)addr;
160 #endif
161  memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun);
162 
163  icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp,
164  sizeof icmp, 0));
165 
166 #if defined (TRACING)
167  if (trace_playback ()) {
168  char *buf = (char *)0;
169  unsigned buflen = 0;
170 
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));
176  if (buf)
177  dfree (buf, MDL);
178  } else {
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,
185  2, iov, MDL);
186  }
187 #endif
188  /* Send the ICMP packet... */
189  status = sendto (icmp_state -> socket,
190  (char *)&icmp, sizeof icmp, 0,
191  (struct sockaddr *)&to, sizeof to);
192  if (status < 0)
193  log_error ("icmp_echorequest %s: %m",
194  inet_ntoa(to.sin_addr));
195 
196  if (status != sizeof icmp)
197  return 0;
198 #if defined (TRACING)
199  }
200 #endif
201  return 1;
202 }
203 
204 isc_result_t icmp_echoreply (h)
205  omapi_object_t *h;
206 {
207  struct icmp *icfrom;
208  struct ip *ip;
209  struct sockaddr_in from;
210  u_int8_t icbuf [1500];
211  int status;
212  SOCKLEN_T sl;
213  int hlen, len;
214  struct iaddr ia;
215  struct icmp_state *state;
216 #if defined (TRACING)
217  trace_iov_t iov [2];
218 #endif
219 
220  state = (struct icmp_state *)h;
221 
222  sl = sizeof from;
223  status = recvfrom (state -> socket, (char *)icbuf, sizeof icbuf, 0,
224  (struct sockaddr *)&from, &sl);
225  if (status < 0) {
226  log_error ("icmp_echoreply: %m");
227  return ISC_R_UNEXPECTED;
228  }
229 
230  /* Find the IP header length... */
231  ip = (struct ip *)icbuf;
232  hlen = IP_HL (ip);
233 
234  /* Short packet? */
235  if (status < hlen + (sizeof *icfrom)) {
236  return ISC_R_SUCCESS;
237  }
238 
239  len = status - hlen;
240  icfrom = (struct icmp *)(icbuf + hlen);
241 
242  /* Silently discard ICMP packets that aren't echoreplies. */
243  if (icfrom -> icmp_type != ICMP_ECHOREPLY) {
244  return ISC_R_SUCCESS;
245  }
246 
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;
251 
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;
258  iov [1].len = len;
259  trace_write_packet_iov (trace_icmp_input, 2, iov, MDL);
260  ia.len = ntohl(ia.len);
261  }
262 #endif
263  (*state -> icmp_handler) (ia, icbuf, len);
264  }
265  return ISC_R_SUCCESS;
266 }
267 
268 #if defined (TRACING)
269 void trace_icmp_input_input (trace_type_t *ttype, unsigned length, char *buf)
270 {
271  struct iaddr *ia;
272  u_int8_t *icbuf;
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));
279 }
280 
281 void trace_icmp_input_stop (trace_type_t *ttype) { }
282 
283 void trace_icmp_output_input (trace_type_t *ttype, unsigned length, char *buf)
284 {
285  struct iaddr ia;
286 
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)));
290  return;
291  }
292  ia.len = 4;
293  memcpy (ia.iabuf, buf, 4);
294 
295  log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia));
296 }
297 
298 void trace_icmp_output_stop (trace_type_t *ttype) { }
299 #endif /* TRACING */
const char * buf
Definition: trace.h:75
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:198
u_int8_t icmp_code
Definition: ip_icmp.h:53
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
void trace_icmp_output_input(trace_type_t *, unsigned, char *)
#define MDL
Definition: omapip.h:567
unsigned char iabuf[16]
Definition: inet.h:33
void icmp_startup(int routep, void *handler)
Definition: icmp.c:47
void trace_icmp_input_stop(trace_type_t *)
#define ICMP_ECHOREPLY
Definition: ip_icmp.h:126
void trace_icmp_input_input(trace_type_t *, unsigned, char *)
int trace_playback(void)
int log_error(const char *,...) __attribute__((__format__(__printf__
unsigned len
Definition: inet.h:32
#define OMAPI_OBJECT_ALLOC(name, stype, type)
Definition: omapip.h:160
struct icmp_state * icmp_state
Definition: icmp.c:34
u_int32_t wrapsum(u_int32_t sum)
Definition: packet.c:83
#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
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: trace.h:76
int socket
Definition: dhcpd.h:1518
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
Definition: ip.h:47
void dfree(void *, const char *, int)
Definition: alloc.c:145
int trace_record(void)
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:193
const char int
Definition: omapip.h:442
isc_result_t trace_get_packet(trace_type_t **, unsigned *, char **)
u_int8_t icmp_type
Definition: ip_icmp.h:52
int icmp_readsocket(omapi_object_t *h)
Definition: icmp.c:119
isc_result_t icmp_echoreply(omapi_object_t *h)
Definition: icmp.c:204
#define ICMP_ECHO
Definition: ip_icmp.h:147
int icmp_echorequest(struct iaddr *addr)
Definition: icmp.c:128
#define SOCKLEN_T
Definition: osdep.h:280
#define RC_MISC
Definition: alloc.h:56
u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
Definition: packet.c:44
union icmp::@2 icmp_dun