8 #include <linux/socket.h>
10 #include <linux/if_eql.h>
13 #include <linux/icmp.h>
14 #include <linux/route.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
19 /* The following portions are extracted from the netkit-base ping sources,
20 and come under this copyright: */
23 * Copyright (c) 1989 The Regents of the University of California.
24 * All rights reserved.
26 * This code is derived from software contributed to Berkeley by
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * Checksum routine for Internet Protocol family headers (C Version)
63 in_cksum(u_short *addr, int len)
65 register int nleft = len;
66 register u_short *w = addr;
71 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
72 * sequential 16 bit words to it, and at the end, fold back all the
73 * carry bits from the top 16 bits into the lower 16 bits.
80 /* mop up an odd byte, if necessary */
82 *(unsigned char *)(&answer) = *(unsigned char *)w ;
86 /* add back carry outs from top 16 bits to low 16 bits */
87 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
88 sum += (sum >> 16); /* add carry */
89 answer = ~sum; /* truncate to 16 bits */
93 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
95 #define ICMP_DEST_UNREACH ICMP_UNREACH
96 #define ICMP_NET_UNREACH ICMP_UNREACH_NET
97 #define ICMP_HOST_UNREACH ICMP_UNREACH_HOST
98 #define ICMP_PORT_UNREACH ICMP_UNREACH_PORT
99 #define ICMP_PROT_UNREACH ICMP_UNREACH_PROTOCOL
100 #define ICMP_FRAG_NEEDED ICMP_UNREACH_NEEDFRAG
101 #define ICMP_SR_FAILED ICMP_UNREACH_SRCFAIL
102 #define ICMP_NET_UNKNOWN ICMP_UNREACH_NET_UNKNOWN
103 #define ICMP_HOST_UNKNOWN ICMP_UNREACH_HOST_UNKNOWN
104 #define ICMP_HOST_ISOLATED ICMP_UNREACH_ISOLATED
105 #define ICMP_NET_UNR_TOS ICMP_UNREACH_TOSNET
106 #define ICMP_HOST_UNR_TOS ICMP_UNREACH_TOSHOST
107 #define ICMP_SOURCE_QUENCH ICMP_SOURCEQUENCH
108 #define ICMP_REDIR_NET ICMP_REDIRECT_NET
109 #define ICMP_REDIR_HOST ICMP_REDIRECT_HOST
110 #define ICMP_REDIR_NETTOS ICMP_REDIRECT_TOSNET
111 #define ICMP_REDIR_HOSTTOS ICMP_REDIRECT_TOSHOST
112 #define ICMP_TIME_EXCEEDED ICMP_TIMXCEED
113 #define ICMP_EXC_TTL ICMP_TIMXCEED_INTRANS
114 #define ICMP_EXC_FRAGTIME ICMP_TIMXCEED_REASS
115 #define ICMP_PARAMETERPROB ICMP_PARAMPROB
116 #define ICMP_TIMESTAMP ICMP_TSTAMP
117 #define ICMP_TIMESTAMPREPLY ICMP_TSTAMPREPLY
118 #define ICMP_INFO_REQUEST ICMP_IREQ
119 #define ICMP_INFO_REPLY ICMP_IREQREPLY
121 #define ICMP_MINLEN 28
122 #define inet_ntoa(x) inet_ntoa(*((struct in_addr *)&(x)))
126 #define DEFDATALEN (64 - 8) /* default data length */
128 #define MAXICMPLEN 76
129 #define MAXPACKET (65536 - 60 - 8)/* max packet size */
130 #define MAXWAIT 10 /* max seconds to wait for response */
131 #define NROUTES 9 /* number of record route slots */
133 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
134 #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
135 #define SET(bit) (A(bit) |= B(bit))
136 #define CLR(bit) (A(bit) &= (~B(bit)))
137 #define TST(bit) (A(bit) & B(bit))
139 /* various options */
141 #define F_FLOOD 0x001
142 #define F_INTERVAL 0x002
143 #define F_NUMERIC 0x004
144 #define F_PINGFILLED 0x008
145 #define F_QUIET 0x010
146 #define F_RROUTE 0x020
147 #define F_SO_DEBUG 0x040
148 #define F_SO_DONTROUTE 0x080
149 #define F_VERBOSE 0x100
151 /* multicast options */
153 #define MULTICAST_NOLOOP 0x001
154 #define MULTICAST_TTL 0x002
155 #define MULTICAST_IF 0x004
157 #if !defined(__GLIBC__) || (__GLIBC__ < 2)
158 #define icmp_type type
159 #define icmp_code code
160 #define icmp_cksum checksum
161 #define icmp_id un.echo.id
162 #define icmp_seq un.echo.sequence
163 #define icmp_gwaddr un.gateway
164 #endif /* __GLIBC__ */
169 #define ip_len tot_len
171 #define ip_off frag_off
173 #define ip_p protocol
178 int transmit_ping(int socket, int ident, int sequence, int timing, unsigned char * outpack, int datalen, struct sockaddr * whereto, int wherelen)
180 register struct icmphdr *icp;
184 icp = (struct icmphdr *)outpack;
185 icp->icmp_type = ICMP_ECHO;
188 icp->icmp_seq = sequence;
189 icp->icmp_id = ident; /* ID */
192 (void)gettimeofday((struct timeval *)&outpack[8],
193 (struct timezone *)NULL);
195 cc = datalen + 8; /* skips ICMP portion */
197 /* compute ICMP checksum here */
198 icp->icmp_cksum = in_cksum((u_short *)icp, cc);
200 i = sendto(socket, (char *)outpack, cc, 0, whereto,
203 /*printf("sendto=%d, errno=%d\n", i, errno);*/
208 int receive_ping(int socket, int ident, int seq, unsigned char * packet, int datalen, struct sockaddr * from, int * fromlen)
210 register struct icmphdr *icp;
214 int orig_fromlen = fromlen ? *fromlen : 0;
215 int packlen = datalen+28;
218 *fromlen = orig_fromlen;
220 cc = recvfrom(socket, (char *)packet, packlen, 0,
223 /*printf("recvfrom=%d, errno=%d\n", cc, errno);*/
228 /* Check the IP header */
229 ip = (struct iphdr *)packet;
230 hlen = ip->ip_hl << 2;
231 if (cc < datalen + ICMP_MINLEN) {
233 printf("too short (wanted at least %d bytes, got %d)\n",
234 datalen+ ICMP_MINLEN, cc);
238 /* Now the ICMP part */
240 icp = (struct icmphdr *)(packet + hlen);
241 if (icp->icmp_type == ICMP_ECHOREPLY) {
242 /* not really needed: any response is good enough */
243 /*if (icp->icmp_seq != seq)
245 /* this happens if more then one ping is going */
246 if (icp->icmp_id != ident) {
247 printf("id was wrong (wanted %d, got %d)\n",
248 ident, icp->icmp_id);
249 return -1; /* 'Twas not our ECHO */
253 /* this happens easily if something is pinging us,
255 /*printf("Not an echoreply (wanted type %d, got %d)\n",
256 ICMP_ECHOREPLY, icp->icmp_type);*/
257 return -1; /* Not an ECHOREPLY */
263 /* loop until timeout seconds go by without a ping response */
264 void pinger(int fd, int timeout, struct sockaddr * whereto, int wherelen)
266 int ident = getpid() & 0xffff;
269 unsigned char packet[28];
272 fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
274 /*printf("couldn't get raw socket\n");*/
290 /*printf("Sending ping, seq=%d, id=%d\n", seq, ident);*/
291 transmit_ping(fd, ident, seq, 0, packet, 0, whereto, wherelen);
296 /* sleep till we get a response, or timeout */
301 s = select(fd+1, &rfds, 0, 0, &tv);
302 /*printf("Got something, with %d.%06.6d seconds remaining\n",
303 tv.tv_sec, tv.tv_usec);*/
308 /* was it a useful response? */
309 if (receive_ping(fd, ident, seq, packet, 0, 0, 0)<0)
310 /* no, so keep waiting. Maybe the
311 response is still in the queue. */
313 /*printf("Got a pong\n");*/
318 /*printf("No response, have missed %d\n", missed);*/
325 /* sleep off any remaining time */
326 select(0, 0,0,0, &tv);