1 /* $OpenBSD: icmp.c,v 1.19 2019/10/03 13:36:15 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 1997, 1998 The Internet Software Consortium. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of The Internet Software Consortium nor the names 17 * of its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * This software has been written for the Internet Software Consortium 35 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 36 * Enterprises. To learn more about the Internet Software Consortium, 37 * see ``http://www.vix.com/isc''. To learn more about Vixie 38 * Enterprises, see ``http://www.vix.com''. 39 */ 40 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 44 #include <arpa/inet.h> 45 46 #include <net/if.h> 47 48 #include <netinet/ip.h> 49 #include <netinet/ip_icmp.h> 50 51 #include <netdb.h> 52 #include <stdio.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include "dhcp.h" 57 #include "tree.h" 58 #include "dhcpd.h" 59 #include "log.h" 60 61 static int icmp_protocol_initialized; 62 static int icmp_protocol_fd; 63 64 /* Initialize the ICMP protocol. */ 65 66 void 67 icmp_startup(int routep, void (*handler)(struct iaddr, u_int8_t *, int)) 68 { 69 struct protoent *proto; 70 int protocol = 1, state; 71 72 /* Only initialize icmp once. */ 73 if (icmp_protocol_initialized) 74 fatalx("attempted to reinitialize icmp protocol"); 75 icmp_protocol_initialized = 1; 76 77 /* Get the protocol number (should be 1). */ 78 if ((proto = getprotobyname("icmp")) != NULL) 79 protocol = proto->p_proto; 80 81 /* Get a raw socket for the ICMP protocol. */ 82 if ((icmp_protocol_fd = socket(AF_INET, SOCK_RAW, protocol)) == -1) 83 fatal("unable to create icmp socket"); 84 85 /* Make sure it does routing... */ 86 state = 0; 87 if (setsockopt(icmp_protocol_fd, SOL_SOCKET, SO_DONTROUTE, 88 &state, sizeof(state)) == -1) 89 fatal("Unable to disable SO_DONTROUTE on ICMP socket"); 90 91 add_protocol("icmp", icmp_protocol_fd, icmp_echoreply, 92 (void *)handler); 93 } 94 95 int 96 icmp_echorequest(struct iaddr *addr) 97 { 98 struct sockaddr_in to; 99 struct icmp icmp; 100 int status; 101 102 if (!icmp_protocol_initialized) 103 fatalx("attempt to use ICMP protocol before initialization."); 104 105 memset(&to, 0, sizeof(to)); 106 to.sin_len = sizeof to; 107 to.sin_family = AF_INET; 108 memcpy(&to.sin_addr, addr->iabuf, sizeof to.sin_addr); /* XXX */ 109 110 memset(&icmp, 0, sizeof(icmp)); 111 icmp.icmp_type = ICMP_ECHO; 112 icmp.icmp_id = getpid() & 0xffff; 113 114 icmp.icmp_cksum = wrapsum(checksum((unsigned char *)&icmp, 115 sizeof(icmp), 0)); 116 117 /* Send the ICMP packet... */ 118 status = sendto(icmp_protocol_fd, &icmp, sizeof(icmp), 0, 119 (struct sockaddr *)&to, sizeof(to)); 120 if (status == -1) 121 log_warn("icmp_echorequest %s", inet_ntoa(to.sin_addr)); 122 123 if (status != sizeof icmp) 124 return 0; 125 return 1; 126 } 127 128 void 129 icmp_echoreply(struct protocol *protocol) 130 { 131 void (*handler)(struct iaddr, u_int8_t *, int); 132 struct sockaddr_in from; 133 u_int8_t icbuf[1500]; 134 struct icmp *icfrom; 135 int status, len; 136 socklen_t salen; 137 struct iaddr ia; 138 139 salen = sizeof from; 140 status = recvfrom(protocol->fd, icbuf, sizeof(icbuf), 0, 141 (struct sockaddr *)&from, &salen); 142 if (status == -1) { 143 log_warn("icmp_echoreply"); 144 return; 145 } 146 147 /* Probably not for us. */ 148 if (status < (sizeof(struct ip)) + (sizeof *icfrom)) 149 return; 150 151 len = status - sizeof(struct ip); 152 icfrom = (struct icmp *)(icbuf + sizeof(struct ip)); 153 154 /* Silently discard ICMP packets that aren't echoreplies. */ 155 if (icfrom->icmp_type != ICMP_ECHOREPLY) 156 return; 157 158 /* If we were given a second-stage handler, call it. */ 159 if (protocol->local) { 160 handler = ((void (*)(struct iaddr, u_int8_t *, int)) 161 protocol->local); 162 memcpy(ia.iabuf, &from.sin_addr, sizeof from.sin_addr); 163 ia.len = sizeof from.sin_addr; 164 (*handler)(ia, icbuf, len); 165 } 166 } 167