Annotation of embedaddon/dhcp/common/icmp.c, revision 1.1
1.1 ! misho 1: /* dhcp.c
! 2:
! 3: ICMP Protocol engine - for sending out pings and receiving
! 4: responses. */
! 5:
! 6: /*
! 7: * Copyright (c) 2011 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: * This software has been written for Internet Systems Consortium
! 30: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
! 31: * To learn more about Internet Systems Consortium, see
! 32: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
! 33: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
! 34: * ``http://www.nominum.com''.
! 35: */
! 36:
! 37: #include "dhcpd.h"
! 38: #include "netinet/ip.h"
! 39: #include "netinet/ip_icmp.h"
! 40:
! 41: struct icmp_state *icmp_state;
! 42: static omapi_object_type_t *dhcp_type_icmp;
! 43: static int no_icmp;
! 44:
! 45: OMAPI_OBJECT_ALLOC (icmp_state, struct icmp_state, dhcp_type_icmp)
! 46:
! 47: #if defined (TRACING)
! 48: trace_type_t *trace_icmp_input;
! 49: trace_type_t *trace_icmp_output;
! 50: #endif
! 51:
! 52: /* Initialize the ICMP protocol. */
! 53:
! 54: void icmp_startup (routep, handler)
! 55: int routep;
! 56: void (*handler) (struct iaddr, u_int8_t *, int);
! 57: {
! 58: struct protoent *proto;
! 59: int protocol = 1;
! 60: int state;
! 61: isc_result_t result;
! 62:
! 63: /* Only initialize icmp once. */
! 64: if (dhcp_type_icmp)
! 65: log_fatal ("attempted to reinitialize icmp protocol");
! 66:
! 67: result = omapi_object_type_register (&dhcp_type_icmp, "icmp",
! 68: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 69: sizeof (struct icmp_state),
! 70: 0, RC_MISC);
! 71:
! 72: if (result != ISC_R_SUCCESS)
! 73: log_fatal ("Can't register icmp object type: %s",
! 74: isc_result_totext (result));
! 75:
! 76: icmp_state_allocate (&icmp_state, MDL);
! 77: icmp_state -> icmp_handler = handler;
! 78:
! 79: #if defined (TRACING)
! 80: trace_icmp_input = trace_type_register ("icmp-input", (void *)0,
! 81: trace_icmp_input_input,
! 82: trace_icmp_input_stop, MDL);
! 83: trace_icmp_output = trace_type_register ("icmp-output", (void *)0,
! 84: trace_icmp_output_input,
! 85: trace_icmp_output_stop, MDL);
! 86:
! 87: /* If we're playing back a trace file, don't create the socket
! 88: or set up the callback. */
! 89: if (!trace_playback ()) {
! 90: #endif
! 91: /* Get the protocol number (should be 1). */
! 92: proto = getprotobyname ("icmp");
! 93: if (proto)
! 94: protocol = proto -> p_proto;
! 95:
! 96: /* Get a raw socket for the ICMP protocol. */
! 97: icmp_state -> socket = socket (AF_INET, SOCK_RAW, protocol);
! 98: if (icmp_state -> socket < 0) {
! 99: no_icmp = 1;
! 100: log_error ("unable to create icmp socket: %m");
! 101: return;
! 102: }
! 103:
! 104: #if defined (HAVE_SETFD)
! 105: if (fcntl (icmp_state -> socket, F_SETFD, 1) < 0)
! 106: log_error ("Can't set close-on-exec on icmp: %m");
! 107: #endif
! 108:
! 109: /* Make sure it does routing... */
! 110: state = 0;
! 111: if (setsockopt (icmp_state -> socket, SOL_SOCKET, SO_DONTROUTE,
! 112: (char *)&state, sizeof state) < 0)
! 113: log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m");
! 114:
! 115: result = (omapi_register_io_object
! 116: ((omapi_object_t *)icmp_state,
! 117: icmp_readsocket, 0, icmp_echoreply, 0, 0));
! 118: if (result != ISC_R_SUCCESS)
! 119: log_fatal ("Can't register icmp handle: %s",
! 120: isc_result_totext (result));
! 121: #if defined (TRACING)
! 122: }
! 123: #endif
! 124: }
! 125:
! 126: int icmp_readsocket (h)
! 127: omapi_object_t *h;
! 128: {
! 129: struct icmp_state *state;
! 130:
! 131: state = (struct icmp_state *)h;
! 132: return state -> socket;
! 133: }
! 134:
! 135: int icmp_echorequest (addr)
! 136: struct iaddr *addr;
! 137: {
! 138: struct sockaddr_in to;
! 139: struct icmp icmp;
! 140: int status;
! 141: #if defined (TRACING)
! 142: trace_iov_t iov [2];
! 143: #endif
! 144:
! 145: if (no_icmp)
! 146: return 1;
! 147: if (!icmp_state)
! 148: log_fatal ("ICMP protocol used before initialization.");
! 149:
! 150: memset (&to, 0, sizeof(to));
! 151: #ifdef HAVE_SA_LEN
! 152: to.sin_len = sizeof to;
! 153: #endif
! 154: to.sin_family = AF_INET;
! 155: to.sin_port = 0; /* unused. */
! 156: memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr); /* XXX */
! 157:
! 158: icmp.icmp_type = ICMP_ECHO;
! 159: icmp.icmp_code = 0;
! 160: icmp.icmp_cksum = 0;
! 161: icmp.icmp_seq = 0;
! 162: #if SIZEOF_STRUCT_IADDR_P == 8
! 163: icmp.icmp_id = (((u_int32_t)(u_int64_t)addr) ^
! 164: (u_int32_t)(((u_int64_t)addr) >> 32));
! 165: #else
! 166: icmp.icmp_id = (u_int32_t)addr;
! 167: #endif
! 168: memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun);
! 169:
! 170: icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp,
! 171: sizeof icmp, 0));
! 172:
! 173: #if defined (TRACING)
! 174: if (trace_playback ()) {
! 175: char *buf = (char *)0;
! 176: unsigned buflen = 0;
! 177:
! 178: /* Consume the ICMP event. */
! 179: status = trace_get_packet (&trace_icmp_output, &buflen, &buf);
! 180: if (status != ISC_R_SUCCESS)
! 181: log_error ("icmp_echorequest: %s",
! 182: isc_result_totext (status));
! 183: if (buf)
! 184: dfree (buf, MDL);
! 185: } else {
! 186: if (trace_record ()) {
! 187: iov [0].buf = (char *)addr;
! 188: iov [0].len = sizeof *addr;
! 189: iov [1].buf = (char *)&icmp;
! 190: iov [1].len = sizeof icmp;
! 191: trace_write_packet_iov (trace_icmp_output,
! 192: 2, iov, MDL);
! 193: }
! 194: #endif
! 195: /* Send the ICMP packet... */
! 196: status = sendto (icmp_state -> socket,
! 197: (char *)&icmp, sizeof icmp, 0,
! 198: (struct sockaddr *)&to, sizeof to);
! 199: if (status < 0)
! 200: log_error ("icmp_echorequest %s: %m",
! 201: inet_ntoa(to.sin_addr));
! 202:
! 203: if (status != sizeof icmp)
! 204: return 0;
! 205: #if defined (TRACING)
! 206: }
! 207: #endif
! 208: return 1;
! 209: }
! 210:
! 211: isc_result_t icmp_echoreply (h)
! 212: omapi_object_t *h;
! 213: {
! 214: struct icmp *icfrom;
! 215: struct ip *ip;
! 216: struct sockaddr_in from;
! 217: u_int8_t icbuf [1500];
! 218: int status;
! 219: SOCKLEN_T sl;
! 220: int hlen, len;
! 221: struct iaddr ia;
! 222: struct icmp_state *state;
! 223: #if defined (TRACING)
! 224: trace_iov_t iov [2];
! 225: #endif
! 226:
! 227: state = (struct icmp_state *)h;
! 228:
! 229: sl = sizeof from;
! 230: status = recvfrom (state -> socket, (char *)icbuf, sizeof icbuf, 0,
! 231: (struct sockaddr *)&from, &sl);
! 232: if (status < 0) {
! 233: log_error ("icmp_echoreply: %m");
! 234: return ISC_R_UNEXPECTED;
! 235: }
! 236:
! 237: /* Find the IP header length... */
! 238: ip = (struct ip *)icbuf;
! 239: hlen = IP_HL (ip);
! 240:
! 241: /* Short packet? */
! 242: if (status < hlen + (sizeof *icfrom)) {
! 243: return ISC_R_SUCCESS;
! 244: }
! 245:
! 246: len = status - hlen;
! 247: icfrom = (struct icmp *)(icbuf + hlen);
! 248:
! 249: /* Silently discard ICMP packets that aren't echoreplies. */
! 250: if (icfrom -> icmp_type != ICMP_ECHOREPLY) {
! 251: return ISC_R_SUCCESS;
! 252: }
! 253:
! 254: /* If we were given a second-stage handler, call it. */
! 255: if (state -> icmp_handler) {
! 256: memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr);
! 257: ia.len = sizeof from.sin_addr;
! 258:
! 259: #if defined (TRACING)
! 260: if (trace_record ()) {
! 261: ia.len = htonl(ia.len);
! 262: iov [0].buf = (char *)&ia;
! 263: iov [0].len = sizeof ia;
! 264: iov [1].buf = (char *)icbuf;
! 265: iov [1].len = len;
! 266: trace_write_packet_iov (trace_icmp_input, 2, iov, MDL);
! 267: ia.len = ntohl(ia.len);
! 268: }
! 269: #endif
! 270: (*state -> icmp_handler) (ia, icbuf, len);
! 271: }
! 272: return ISC_R_SUCCESS;
! 273: }
! 274:
! 275: #if defined (TRACING)
! 276: void trace_icmp_input_input (trace_type_t *ttype, unsigned length, char *buf)
! 277: {
! 278: struct iaddr *ia;
! 279: u_int8_t *icbuf;
! 280: ia = (struct iaddr *)buf;
! 281: ia->len = ntohl(ia->len);
! 282: icbuf = (u_int8_t *)(ia + 1);
! 283: if (icmp_state -> icmp_handler)
! 284: (*icmp_state -> icmp_handler) (*ia, icbuf,
! 285: (int)(length - sizeof ia));
! 286: }
! 287:
! 288: void trace_icmp_input_stop (trace_type_t *ttype) { }
! 289:
! 290: void trace_icmp_output_input (trace_type_t *ttype, unsigned length, char *buf)
! 291: {
! 292: struct icmp *icmp;
! 293: struct iaddr ia;
! 294:
! 295: if (length != (sizeof (*icmp) + (sizeof ia))) {
! 296: log_error ("trace_icmp_output_input: data size mismatch %d:%d",
! 297: length, (int)((sizeof (*icmp)) + (sizeof ia)));
! 298: return;
! 299: }
! 300: ia.len = 4;
! 301: memcpy (ia.iabuf, buf, 4);
! 302: icmp = (struct icmp *)(buf + 1);
! 303:
! 304: log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia));
! 305: }
! 306:
! 307: void trace_icmp_output_stop (trace_type_t *ttype) { }
! 308: #endif /* TRACING */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>