1 /* send out an IKE "ping" packet.
2 * Copyright (C) 2002 Michael Richardson
3 * Copyright (C) 2002 D. Hugh Redelmeier.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * RCSID $Id: ikeping.c,v 1.2 2002/03/05 03:24:20 mcr Exp $
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
36 #include "pluto/constants.h"
37 #include "pluto/packet.h"
39 #ifndef ISAKMP_XCHG_ECHOREQUEST
40 #define ISAKMP_XCHG_ECHOREQUEST 30 /* Echo Request */
41 #define ISAKMP_XCHG_ECHOREPLY 31 /* Echo Reply */
44 #ifndef ISAKMP_XCGH_ECHOREQUEST_PRIV
45 #define ISAKMP_XCHG_ECHOREQUEST_PRIV 244 /* Private Echo Request */
46 #define ISAKMP_XCHG_ECHOREPLY_PRIV 245 /* Private Echo Reply */
50 /* what exchange number to use for outgoing requests */
51 static int exchange_number;
59 " [--listen] causes IKEping to open a socket and reply to requests.\n"
60 " [--verbose] causes IKEping to hexdump all packets sent/received.\n"
61 " [--ikeport <port-number>] port to listen on/send from\n"
62 " [--ikeaddress <address>] address to listen on/send from\n"
63 " [--inet] just send/listen on IPv4 socket\n"
64 " [--inet6] just send/listen on IPv6 socket\n"
65 " [--version] just dump version number and exit\n"
66 " [--exchangenum num] use num instead of 244 for the exchange type.\n"
67 " [--wait seconds] time to wait for replies, defaults to 10 seconds.\n"
70 ipsec_version_code());
74 hton_ping(struct isakmp_hdr *ih)
80 /* put it in network byte order. */
81 /* cookies are byte viewed anyway */
83 ih->isa_msgid = htonl(ih->isa_msgid);
84 ih->isa_length = htonl(ih->isa_length);
88 ntoh_ping(struct isakmp_hdr *ih)
94 /* put it in network byte order. */
95 /* cookies are byte viewed anyway */
97 ih->isa_msgid = ntohl(ih->isa_msgid);
98 ih->isa_length = ntohl(ih->isa_length);
107 send_ping(int afamily,
112 struct isakmp_hdr ih;
115 for(i=0; i<COOKIE_SIZE; i++) {
116 ih.isa_icookie[i]=rand()&0xff;
119 for(i=0; i<COOKIE_SIZE; i++) {
120 ih.isa_rcookie[i]=rand()&0xff;
123 ih.isa_np = NOTHING_WRONG;
124 ih.isa_version = (1 << ISA_MAJ_SHIFT) | 0;
125 ih.isa_xchg = (exchange_number ?
126 exchange_number : ISAKMP_XCHG_ECHOREQUEST_PRIV);
128 ih.isa_msgid =rand();
133 raddr->u.v4.sin_port = htons(rport);
134 raddrlen=sizeof(raddr->u.v4);
138 raddr->u.v6.sin6_port = htons(rport);
139 raddrlen=sizeof(raddr->u.v6);
145 if(sendto(s, &ih, sizeof(ih), 0, (struct sockaddr *)raddr, raddrlen) < 0) {
156 reply_packet(int afamily,
158 ip_address *dst_addr,
160 struct isakmp_hdr *op)
164 tmp=afamily; /* shut up compiler */
166 for(i=0; i<COOKIE_SIZE; i++) {
167 tmp=op->isa_icookie[i];
168 op->isa_icookie[i]=op->isa_rcookie[i];
169 op->isa_rcookie[i]=tmp;
172 op->isa_np = NOTHING_WRONG;
173 op->isa_version = (1 << ISA_MAJ_SHIFT) | 0;
174 op->isa_xchg = ISAKMP_XCHG_ECHOREPLY;
176 op->isa_msgid =rand();
181 if(sendto(s, op, sizeof(*op), 0, (struct sockaddr *)dst_addr, dst_len) < 0) {
188 * receive and decode packet.
192 receive_ping(int afamily, int s, int reply)
195 struct isakmp_hdr ih;
197 int n, rport, sendlen;
198 const char *xchg_name;
201 sendlen=sizeof(sender);
202 n = recvfrom(s, &ih, sizeof(ih), 0, (struct sockaddr *)&sender, &sendlen);
204 addrtot(&sender, 0, buf, sizeof(buf));
207 rport = sender.u.v4.sin_port;
211 rport = sender.u.v6.sin6_port;
215 if((unsigned int)n < sizeof(ih)) {
216 fprintf(stderr, "read short packet (%d) from %s/%d\n",
221 /* translate from network byte order */
225 if(ih.isa_xchg == ISAKMP_XCHG_ECHOREQUEST ||
226 ih.isa_xchg == ISAKMP_XCHG_ECHOREQUEST_PRIV ||
227 (exchange_number!=0 && ih.isa_xchg == exchange_number)) {
228 xchg_name="echo-request";
229 xchg=ISAKMP_XCHG_ECHOREQUEST;
230 } else if(ih.isa_xchg == ISAKMP_XCHG_ECHOREPLY ||
231 ih.isa_xchg == ISAKMP_XCHG_ECHOREPLY_PRIV ||
232 (exchange_number!=0 && ih.isa_xchg == exchange_number+1)) {
233 xchg_name="echo-reply";
238 printf("received %d(%s) packet from %s/%d of len: %d\n",
239 ih.isa_xchg, xchg_name, buf, ntohs(rport), n);
240 printf("\trcookie=%08x_%08x icookie=%08x_%08x msgid=%08x\n",
241 *(u_int32_t *)(ih.isa_icookie),
242 *(u_int32_t *)(ih.isa_icookie+4),
243 *(u_int32_t *)(ih.isa_rcookie),
244 *(u_int32_t *)(ih.isa_rcookie+4),
246 printf("\tnp=%03d version=%d.%d xchg=%s(%d)\n",
248 ih.isa_version >> ISA_MAJ_SHIFT,
249 ih.isa_version & ISA_MIN_MASK,
253 if(reply && xchg==ISAKMP_XCHG_ECHOREQUEST) {
254 reply_packet(afamily, s, &sender, sendlen, &ih);
258 static const struct option long_opts[] = {
259 /* name, has_arg, flag, val */
260 { "help", no_argument, NULL, 'h' },
261 { "version", no_argument, NULL, 'V' },
262 { "verbose", no_argument, NULL, 'v' },
263 { "listen", no_argument, NULL, 's' },
264 { "ikeport", required_argument, NULL, 'p' },
265 { "ikeaddress", required_argument, NULL, 'b' },
266 { "inet", no_argument, NULL, '4' },
267 { "inet6", no_argument, NULL, '6' },
268 { "exchangenum", required_argument, NULL, 'n' },
269 { "wait", required_argument, NULL, 'w' },
274 main(int argc, char **argv)
284 int numSenders, numReceived, noDNS;
286 int verbose, timedOut;
287 ip_address laddr, raddr;
297 bzero(&laddr, sizeof(laddr));
299 while((c = getopt_long(argc, argv, "hVnvsp:b:46E:w:", long_opts, 0))!=EOF) {
301 case 'h': /* --help */
303 return 0; /* GNU coding standards say to stop here */
305 case 'V': /* --version */
306 fprintf(stderr, "FreeS/WAN %s\n", ipsec_version_code());
307 return 0; /* GNU coding standards say to stop here */
309 case 'v': /* --label <string> */
318 exchange_number=strtol(optarg, &foo, 0);
319 if(optarg==foo || exchange_number < 1 || exchange_number>255) {
320 fprintf(stderr, "Invalid exchange number '%s' (should be 1<=x<255)\n",
332 lport=strtol(optarg, &foo, 0);
333 if(optarg==foo || lport <0 || lport>65535) {
334 fprintf(stderr, "Invalid port number '%s' (should be 0<=x<65536)\n",
341 waitTime=strtol(optarg, &foo, 0);
342 if(optarg==foo || waitTime < 0) {
343 fprintf(stderr, "Invalid waittime number '%s' (should be 0<=x)\n",
350 errstr = ttoaddr(optarg, strlen(optarg), afamily, &laddr);
352 fprintf(stderr, "Invalid local address '%s': %s\n",
369 assert(FALSE); /* unknown return value */
373 s=socket(pfamily, SOCK_DGRAM, IPPROTO_UDP);
381 laddr.u.v4.sin_port = htons(lport);
382 if(bind(s, (struct sockaddr *)&laddr.u.v4, sizeof(laddr.u.v4)) < 0) {
389 laddr.u.v6.sin6_port = htons(lport);
390 if(bind(s, (struct sockaddr *)&laddr.u.v6, sizeof(laddr.u.v6)) < 0) {
400 while(optind < argc) {
407 port = strchr(host, '/');
412 dport= strtol(port, &foo, 0);
413 if(port==foo || dport < 0 || dport > 65535) {
414 fprintf(stderr, "Invalid port number '%s' "
415 "(should be 0<=x<65536)\n",
421 errstr = ttoaddr(host, strlen(host),
424 fprintf(stderr, "Invalid remote address '%s': %s\n",
429 addrtot(&raddr, 0, namebuf, sizeof(namebuf));
431 printf("Sending packet to %s/%d\n", namebuf, dport);
433 send_ping(afamily, s, &raddr, dport);
442 /* really should catch ^C and print stats on exit */
443 while(numSenders > 0 || listen_only) {
448 ready.events = POLLIN;
450 n = poll(&ready, 1, waitTime);
456 if(n == 0 && !listen_only) {
462 receive_ping(afamily, s, listen_only);
466 if(numReceived > 0) {
467 printf("%d packets sent, %d packets received. %d packet loss\n",
468 numSenders, numReceived, numSenders*100/numReceived);
475 * c-file-style: "linux"