]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/icmp.c
Update license.
[thirdparty/dhcp.git] / common / icmp.c
1 /* dhcp.c
2
3 ICMP Protocol engine - for sending out pings and receiving
4 responses. */
5
6 /*
7 * Copyright (c) 1996-1999 Internet Software Consortium.
8 * Use is subject to license terms which appear in the file named
9 * ISC-LICENSE that should have accompanied this file when you
10 * received it. If a file named ISC-LICENSE did not accompany this
11 * file, or you are not sure the one you have is correct, you may
12 * obtain an applicable copy of the license at:
13 *
14 * http://www.isc.org/isc-license-1.0.html.
15 *
16 * This file is part of the ISC DHCP distribution. The documentation
17 * associated with this file is listed in the file DOCUMENTATION,
18 * included in the top-level directory of this release.
19 *
20 * Support and other services are available for ISC products - see
21 * http://www.isc.org for more information.
22 */
23
24 #ifndef lint
25 static char copyright[] =
26 "$Id: icmp.c,v 1.13 1999/03/16 05:50:34 mellon Exp $ Copyright (c) 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
27 #endif /* not lint */
28
29 #include "dhcpd.h"
30 #include "netinet/ip.h"
31 #include "netinet/ip_icmp.h"
32
33 static int icmp_protocol_initialized;
34 static int icmp_protocol_fd;
35
36 /* Initialize the ICMP protocol. */
37
38 void icmp_startup (routep, handler)
39 int routep;
40 void (*handler) PROTO ((struct iaddr, u_int8_t *, int));
41 {
42 struct protoent *proto;
43 int protocol = 1;
44 struct sockaddr_in from;
45 int fd;
46 int state;
47
48 /* Only initialize icmp once. */
49 if (icmp_protocol_initialized)
50 log_fatal ("attempted to reinitialize icmp protocol");
51 icmp_protocol_initialized = 1;
52
53 /* Get the protocol number (should be 1). */
54 proto = getprotobyname ("icmp");
55 if (proto)
56 protocol = proto -> p_proto;
57
58 /* Get a raw socket for the ICMP protocol. */
59 icmp_protocol_fd = socket (AF_INET, SOCK_RAW, protocol);
60 if (icmp_protocol_fd < 0)
61 log_fatal ("unable to create icmp socket: %m");
62
63 /* Make sure it does routing... */
64 state = 0;
65 if (setsockopt (icmp_protocol_fd, SOL_SOCKET, SO_DONTROUTE,
66 (char *)&state, sizeof state) < 0)
67 log_fatal ("Unable to disable SO_DONTROUTE on ICMP socket: %m");
68
69 add_protocol ("icmp", icmp_protocol_fd,
70 icmp_echoreply, (void *)handler);
71 }
72
73 int icmp_echorequest (addr)
74 struct iaddr *addr;
75 {
76 struct sockaddr_in to;
77 struct icmp icmp;
78 int status;
79
80 if (!icmp_protocol_initialized)
81 log_fatal ("attempt to use ICMP protocol before initialization.");
82
83 #ifdef HAVE_SA_LEN
84 to.sin_len = sizeof to;
85 #endif
86 to.sin_family = AF_INET;
87 to.sin_port = 0; /* unused. */
88 memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr); /* XXX */
89
90 icmp.icmp_type = ICMP_ECHO;
91 icmp.icmp_code = 0;
92 icmp.icmp_cksum = 0;
93 icmp.icmp_seq = 0;
94 #ifdef PTRSIZE_64BIT
95 icmp.icmp_id = (((u_int32_t)(u_int64_t)addr) ^
96 (u_int32_t)(((u_int64_t)addr) >> 32));
97 #else
98 icmp.icmp_id = (u_int32_t)addr;
99 #endif
100 memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun);
101
102 icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp,
103 sizeof icmp, 0));
104
105 /* Send the ICMP packet... */
106 status = sendto (icmp_protocol_fd, (char *)&icmp, sizeof icmp, 0,
107 (struct sockaddr *)&to, sizeof to);
108 if (status < 0)
109 log_error ("icmp_echorequest %s: %m", inet_ntoa(to.sin_addr));
110
111 if (status != sizeof icmp)
112 return 0;
113 return 1;
114 }
115
116 void icmp_echoreply (protocol)
117 struct protocol *protocol;
118 {
119 struct icmp *icfrom;
120 struct ip *ip;
121 struct sockaddr_in from;
122 unsigned char icbuf [1500];
123 int status;
124 int len, hlen;
125 struct iaddr ia;
126 void (*handler) PROTO ((struct iaddr, u_int8_t *, int));
127
128 len = sizeof from;
129 status = recvfrom (protocol -> fd, (char *)icbuf, sizeof icbuf, 0,
130 (struct sockaddr *)&from, &len);
131 if (status < 0) {
132 log_error ("icmp_echoreply: %m");
133 return;
134 }
135
136 /* Find the IP header length... */
137 ip = (struct ip *)icbuf;
138 hlen = ip -> ip_hl << 2;
139
140 /* Short packet? */
141 if (status < hlen + (sizeof *icfrom)) {
142 return;
143 }
144
145 len = status - hlen;
146 icfrom = (struct icmp *)(icbuf + hlen);
147
148 /* Silently discard ICMP packets that aren't echoreplies. */
149 if (icfrom -> icmp_type != ICMP_ECHOREPLY) {
150 return;
151 }
152
153 /* If we were given a second-stage handler, call it. */
154 if (protocol -> local) {
155 handler = ((void (*) PROTO ((struct iaddr, u_int8_t *, int)))
156 protocol -> local);
157 memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr);
158 ia.len = sizeof from.sin_addr;
159
160 (*handler) (ia, icbuf, len);
161 }
162 }