OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / testing / utils / ikeping / ikeping.c
1 /* send out an IKE "ping" packet.
2  * Copyright (C) 2002 Michael Richardson
3  * Copyright (C) 2002 D. Hugh Redelmeier.
4  *
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>.
9  *
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
13  * for more details.
14  *
15  * RCSID $Id: ikeping.c,v 1.2 2002/03/05 03:24:20 mcr Exp $
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <getopt.h>
31 #include <assert.h>
32 #include <poll.h>
33
34 #include <freeswan.h>
35
36 #include "pluto/constants.h"
37 #include "pluto/packet.h"
38
39 #ifndef ISAKMP_XCHG_ECHOREQUEST
40 #define ISAKMP_XCHG_ECHOREQUEST 30      /* Echo Request */
41 #define ISAKMP_XCHG_ECHOREPLY   31      /* Echo Reply   */
42 #endif
43
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   */
47 #endif
48
49
50 /* what exchange number to use for outgoing requests */
51 static int exchange_number;
52
53 static void
54 help(void)
55 {
56     fprintf(stderr,
57         "Usage:\n\n"
58         "ikeping"
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"
68             " host/port ...\n\n"
69         "FreeS/WAN %s\n",
70         ipsec_version_code());
71 }
72
73 static void
74 hton_ping(struct isakmp_hdr *ih)
75 {
76         u_int32_t *ihp;
77
78         ihp=(u_int32_t *)ih;
79
80         /* put it in network byte order. */
81         /* cookies are byte viewed anyway */
82         ihp[4]=htonl(ihp[4]);
83         ih->isa_msgid  = htonl(ih->isa_msgid);
84         ih->isa_length = htonl(ih->isa_length);
85 }
86
87 static void
88 ntoh_ping(struct isakmp_hdr *ih)
89 {
90         u_int32_t *ihp;
91
92         ihp=(u_int32_t *)ih;
93
94         /* put it in network byte order. */
95         /* cookies are byte viewed anyway */
96         ihp[4]=ntohl(ihp[4]);
97         ih->isa_msgid  = ntohl(ih->isa_msgid);
98         ih->isa_length = ntohl(ih->isa_length);
99 }
100
101
102 /*
103  * send an IKE ping
104  *
105  */
106 static void
107 send_ping(int afamily,
108           int s,
109           ip_address *raddr,
110           int rport)
111 {
112         struct isakmp_hdr ih;
113         int i, raddrlen;
114
115         for(i=0; i<COOKIE_SIZE; i++) {
116                 ih.isa_icookie[i]=rand()&0xff;          
117         }
118              
119         for(i=0; i<COOKIE_SIZE; i++) {
120                 ih.isa_rcookie[i]=rand()&0xff;          
121         }
122              
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);
127         ih.isa_flags =0;
128         ih.isa_msgid =rand();
129         ih.isa_length=0;
130
131         switch(afamily) {
132         case AF_INET:
133                 raddr->u.v4.sin_port = htons(rport);
134                 raddrlen=sizeof(raddr->u.v4);
135                 break;
136           
137         case AF_INET6:
138                 raddr->u.v6.sin6_port = htons(rport);
139                 raddrlen=sizeof(raddr->u.v6);
140                 break;
141         }
142
143         hton_ping(&ih);
144
145         if(sendto(s, &ih, sizeof(ih), 0, (struct sockaddr *)raddr, raddrlen) < 0) {
146                 perror("sendto");
147                 exit(5);
148         }
149 }
150
151 /*
152  * send an IKE ping
153  *
154  */
155 static void
156 reply_packet(int afamily,
157              int s,
158              ip_address *dst_addr,
159              int         dst_len,
160              struct isakmp_hdr *op)
161 {
162         int i, tmp;
163
164         tmp=afamily;  /* shut up compiler */
165
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;
170         }
171              
172         op->isa_np    = NOTHING_WRONG;
173         op->isa_version = (1 << ISA_MAJ_SHIFT) | 0;
174         op->isa_xchg  = ISAKMP_XCHG_ECHOREPLY;
175         op->isa_flags =0;
176         op->isa_msgid =rand();
177         op->isa_length=0;
178
179         hton_ping(op);
180
181         if(sendto(s, op, sizeof(*op), 0, (struct sockaddr *)dst_addr, dst_len) < 0) {
182                 perror("sendto");
183                 exit(5);
184         }
185 }
186
187 /*
188  * receive and decode packet.
189  *
190  */
191 static void
192 receive_ping(int afamily, int s, int reply)
193 {
194         ip_address sender;
195         struct isakmp_hdr ih;
196         char   buf[64];
197         int n, rport, sendlen;
198         const char *xchg_name;
199         int xchg;
200
201         sendlen=sizeof(sender);
202         n = recvfrom(s, &ih, sizeof(ih), 0, (struct sockaddr *)&sender, &sendlen);
203
204         addrtot(&sender, 0, buf, sizeof(buf));
205         switch(afamily) {
206         case AF_INET:
207                 rport = sender.u.v4.sin_port;
208                 break;
209           
210         case AF_INET6:
211                 rport = sender.u.v6.sin6_port;
212                 break;
213         }
214
215         if((unsigned int)n < sizeof(ih)) {
216                 fprintf(stderr, "read short packet (%d) from %s/%d\n",
217                         n, buf, rport);
218                 return;
219         }
220
221         /* translate from network byte order */
222         ntoh_ping(&ih);
223
224
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";
234         } else {
235                 xchg_name="";
236         }
237
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),
245                ih.isa_msgid);
246         printf("\tnp=%03d  version=%d.%d    xchg=%s(%d)\n",
247                ih.isa_np,
248                ih.isa_version >> ISA_MAJ_SHIFT,
249                ih.isa_version & ISA_MIN_MASK,
250                xchg_name,
251                ih.isa_xchg);
252
253         if(reply && xchg==ISAKMP_XCHG_ECHOREQUEST) {
254                 reply_packet(afamily, s, &sender, sendlen, &ih);
255         }
256 }
257
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' },
270     { 0,0,0,0 }
271 };
272
273 int
274 main(int argc, char **argv)
275 {
276   char *foo;
277   const char *errstr;
278   int   s;
279   int   listen_only;
280   int   lport,dport;
281   int   afamily;
282   int   pfamily;
283   int   c;
284   int   numSenders, numReceived, noDNS;
285   int   waitTime;
286   int   verbose, timedOut;
287   ip_address laddr, raddr;
288
289   afamily=AF_INET;
290   pfamily=PF_INET;
291   lport=500;
292   dport=500;
293   waitTime=10;
294   verbose=0;
295   listen_only=0;
296   noDNS=0;
297   bzero(&laddr, sizeof(laddr));
298
299   while((c = getopt_long(argc, argv, "hVnvsp:b:46E:w:", long_opts, 0))!=EOF) {
300     switch (c) {
301       case 'h':         /* --help */
302         help();
303         return 0;       /* GNU coding standards say to stop here */
304         
305       case 'V':               /* --version */
306         fprintf(stderr, "FreeS/WAN %s\n", ipsec_version_code());
307         return 0;       /* GNU coding standards say to stop here */
308         
309       case 'v': /* --label <string> */
310         verbose++;
311         continue;
312         
313       case 'n':
314               noDNS=1;
315               break;
316         
317       case 'E':
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",
321                   optarg);
322           exit(1);
323         }
324         continue;
325         
326         
327       case 's':
328         listen_only++;
329         continue;
330         
331       case 'p':
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",
335                   optarg);
336           exit(1);
337         }
338         continue;
339         
340       case 'w':
341         waitTime=strtol(optarg, &foo, 0);
342         if(optarg==foo || waitTime < 0) {
343           fprintf(stderr, "Invalid waittime number '%s' (should be 0<=x)\n",
344                   optarg);
345           exit(1);
346         }
347         continue;
348         
349       case 'b':
350         errstr = ttoaddr(optarg, strlen(optarg), afamily, &laddr);
351         if(errstr!=NULL) {
352           fprintf(stderr, "Invalid local address '%s': %s\n",
353                   optarg, errstr);
354           exit(1);
355         }
356         continue;
357         
358       case '4':
359         afamily=AF_INET;
360         pfamily=PF_INET;
361         continue;
362         
363       case '6':
364         afamily=AF_INET6;
365         pfamily=PF_INET6;
366         continue;
367         
368       default:
369         assert(FALSE);  /* unknown return value */
370     }
371   }
372
373   s=socket(pfamily, SOCK_DGRAM, IPPROTO_UDP);
374   if(s < 0) {
375     perror("socket");
376     exit(3);
377   }
378
379   switch(afamily) {
380   case AF_INET:
381           laddr.u.v4.sin_port = htons(lport);
382           if(bind(s, (struct sockaddr *)&laddr.u.v4, sizeof(laddr.u.v4)) < 0) {
383                   perror("v4 bind");
384                   exit(5);
385           }
386           break;
387           
388   case AF_INET6:
389           laddr.u.v6.sin6_port = htons(lport);
390           if(bind(s, (struct sockaddr *)&laddr.u.v6, sizeof(laddr.u.v6)) < 0) {
391                   perror("v6 bind");
392                   exit(5);
393           }
394           break;
395   }
396
397   numSenders = 0;
398
399   if(!listen_only) {
400           while(optind < argc) {
401                   char *port;
402                   char *host;
403                   char  namebuf[128];
404
405                   host = argv[optind];
406
407                   port = strchr(host, '/');
408                   dport=500;
409                   if(port) {
410                          *port='\0';
411                           port++;
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",
416                                           port);
417                                   exit(1);
418                           }
419                   }
420
421                   errstr = ttoaddr(host, strlen(host),
422                                    afamily, &raddr);
423                   if(errstr!=NULL) {
424                           fprintf(stderr, "Invalid remote address '%s': %s\n",
425                                   host, errstr);
426                           exit(1);
427                   }
428
429                   addrtot(&raddr, 0, namebuf, sizeof(namebuf));
430
431                   printf("Sending packet to %s/%d\n", namebuf, dport);
432                          
433                   send_ping(afamily, s, &raddr, dport);
434                   numSenders++;
435                   optind++;
436           }
437   }
438
439   timedOut = 0;
440   numReceived=0;
441
442   /* really should catch ^C and print stats on exit */
443   while(numSenders > 0 || listen_only) {
444           struct pollfd  ready;
445           int n;
446
447           ready.fd = s;
448           ready.events = POLLIN;
449
450           n = poll(&ready, 1, waitTime);
451           if(n < 0) {
452                   perror("poll");
453                   exit(1);
454           }
455           
456           if(n == 0 && !listen_only) {
457                   break;
458           }
459
460           if(n == 1) {
461                   numReceived++;
462                   receive_ping(afamily, s, listen_only);
463           }
464   }
465
466   if(numReceived > 0) {
467     printf("%d packets sent, %d packets received. %d packet loss\n",
468            numSenders, numReceived, numSenders*100/numReceived);
469   }
470   exit(0);
471 }
472
473 /*
474  * Local variables:
475  * c-file-style: "linux"
476  * c-basic-offset: 4
477  * End:
478  *
479  */