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