diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2006-05-22 05:12:18 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2006-05-22 05:12:18 +0000 |
commit | aa0f5b38aec14428b4b80e06f90ff781f8bca5f1 (patch) | |
tree | 95f3d0c8cb0d59d88900dbbd72110d7ab6e15b2a /programs/ikeping | |
parent | 7c383bc22113b23718be89fe18eeb251942d7356 (diff) | |
download | vyos-strongswan-aa0f5b38aec14428b4b80e06f90ff781f8bca5f1.tar.gz vyos-strongswan-aa0f5b38aec14428b4b80e06f90ff781f8bca5f1.zip |
Import initial strongswan 2.7.0 version into SVN.
Diffstat (limited to 'programs/ikeping')
-rw-r--r-- | programs/ikeping/.cvsignore | 1 | ||||
-rw-r--r-- | programs/ikeping/Makefile | 57 | ||||
-rw-r--r-- | programs/ikeping/ikeping.8 | 71 | ||||
-rw-r--r-- | programs/ikeping/ikeping.c | 483 |
4 files changed, 612 insertions, 0 deletions
diff --git a/programs/ikeping/.cvsignore b/programs/ikeping/.cvsignore new file mode 100644 index 000000000..755295a5f --- /dev/null +++ b/programs/ikeping/.cvsignore @@ -0,0 +1 @@ +ikeping diff --git a/programs/ikeping/Makefile b/programs/ikeping/Makefile new file mode 100644 index 000000000..6c7b31d59 --- /dev/null +++ b/programs/ikeping/Makefile @@ -0,0 +1,57 @@ +# Makefile for the KLIPS interface utilities +# Copyright (C) 1998, 1999 Henry Spencer. +# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $ + +FREESWANSRCDIR=../.. +include ${FREESWANSRCDIR}/Makefile.inc + +PROGRAM=ikeping +LIBS=${FREESWANLIB} + +ifeq ($(USE_IKEPING),false) +NOINSTALL=true +install: + # do nothing + +install_file_list: + # do nothing + +endif + +include ../Makefile.program + +# +# $Log: Makefile,v $ +# Revision 1.1 2004/03/15 20:35:27 as +# added files from freeswan-2.04-x509-1.5.3 +# +# Revision 1.4 2003/06/29 21:34:49 mcr +# added "NOINSTALL" to omit install: target from common +# Makefile so that it can be overridden +# +# Revision 1.3 2003/06/25 03:57:45 mcr +# build, but do not install "ikeping" even when we do not +# want it as part of the system. +# +# Revision 1.2 2002/06/02 22:02:14 mcr +# changed TOPDIR->FREESWANSRCDIR in all Makefiles. +# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the +# kernel sense.) +# +# Revision 1.1 2002/04/24 07:55:32 mcr +# #include patches and Makefiles for post-reorg compilation. +# +# +# diff --git a/programs/ikeping/ikeping.8 b/programs/ikeping/ikeping.8 new file mode 100644 index 000000000..a9b80b46d --- /dev/null +++ b/programs/ikeping/ikeping.8 @@ -0,0 +1,71 @@ +.TH IPSEC_IKEPING 8 "23 Feb 2002" +.\" RCSID $Id: ikeping.8,v 1.1 2004/03/15 20:35:27 as Exp $ +.SH NAME +ipsec ikeping \- send/receive ISAKMP/IKE echo requests/replies +.SH SYNOPSIS +.B ipsec +.B ikeping +[ +.B \-\-listen +] [ +.B \-\-verbose +] [ +.B \-\-wait +time ] [ +.B \-\-exchangenum +num ] [ +.B \-\-ikeport +localport ] [ +.B \-\-ikeaddress +address ] [ +.B \-\-inet +] [ +.B \-\-inet6 +] destaddr[/dstport] ... +.SH DESCRIPTION +.I Ikeping +sends and receives ISAKMP/IKE echo request and echo reply packets. These +packets are intended for diagnostics purposes, in a manner similar to +.IR ping (8) +does for ICMP echo request/reply packets. +.PP +At the time of this writing, the ISAKMP echo request/reply exchange is still +an internet-draft, and is therefore completely non-standard. +.PP +.I Ikeping +will bind to the local address given by +.B \-\-ikeaddress +and the port number given by +.B \-\-ikeport +defaulting to the wildcard address and the ISAKMP port 500. An ISAKMP +exchange of type 244 (a private use number) is sent to each of the +address/ports listed on the command line. The exchange number may be +overridden by the +.B \-\-exchangenum +option. +.PP +.I Ikeping +then listens for replies, printing them as they are received. Replies +are of exchange type 245 or the specified exchange number plus 1. +.I Ikeping +will keep listening until it either receives as many echo responses as it sent, +or until the timeout period (10 seconds) has been reached. Receipt of a +packet will reset the timer. The +.B \-\-wait +option can be used to specify a different timeout period. +.PP +If the +.B \-\-listen +option is given, then +.I ikeping +will not send any packets. Instead, it will listen for them and reply to +each request received. +.SH FILES +no external files +.SH SEE ALSO +ping(8), ipsec_pluto(8) +.SH HISTORY +Written for the Linux FreeS/WAN project +<http://www.freeswan.org> +by Michael Richardson. +.SH BUGS diff --git a/programs/ikeping/ikeping.c b/programs/ikeping/ikeping.c new file mode 100644 index 000000000..7efb26ad7 --- /dev/null +++ b/programs/ikeping/ikeping.c @@ -0,0 +1,483 @@ +/* send out an IKE "ping" packet. + * Copyright (C) 2002 Michael Richardson + * Copyright (C) 2002 D. Hugh Redelmeier. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: ikeping.c,v 1.1 2004/03/15 20:35:27 as Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <getopt.h> +#include <assert.h> +#include <poll.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/packet.h" + +#ifndef ISAKMP_XCHG_ECHOREQUEST +#define ISAKMP_XCHG_ECHOREQUEST 30 /* Echo Request */ +#define ISAKMP_XCHG_ECHOREPLY 31 /* Echo Reply */ +#endif + +#ifndef ISAKMP_XCGH_ECHOREQUEST_PRIV +#define ISAKMP_XCHG_ECHOREQUEST_PRIV 244 /* Private Echo Request */ +#define ISAKMP_XCHG_ECHOREPLY_PRIV 245 /* Private Echo Reply */ +#endif + + +/* what exchange number to use for outgoing requests */ +static int exchange_number; + +static void +help(void) +{ + fprintf(stderr, + "Usage:\n\n" + "ikeping" + " [--listen] causes IKEping to open a socket and reply to requests.\n" + " [--verbose] causes IKEping to hexdump all packets sent/received.\n" + " [--ikeport <port-number>] port to listen on/send from\n" + " [--ikeaddress <address>] address to listen on/send from\n" + " [--inet] just send/listen on IPv4 socket\n" + " [--inet6] just send/listen on IPv6 socket\n" + " [--version] just dump version number and exit\n" + " [--exchangenum num] use num instead of 244 for the exchange type.\n" + " [--wait seconds] time to wait for replies, defaults to 10 seconds.\n" + " host/port ...\n\n" + "FreeS/WAN %s\n", + ipsec_version_code()); +} + +static void +hton_ping(struct isakmp_hdr *ih) +{ + u_int32_t *ihp; + + ihp=(u_int32_t *)ih; + + /* put it in network byte order. */ + /* cookies are byte viewed anyway */ + ihp[4]=htonl(ihp[4]); + ih->isa_msgid = htonl(ih->isa_msgid); + ih->isa_length = htonl(ih->isa_length); +} + +static void +ntoh_ping(struct isakmp_hdr *ih) +{ + u_int32_t *ihp; + + ihp=(u_int32_t *)ih; + + /* put it in network byte order. */ + /* cookies are byte viewed anyway */ + ihp[4]=ntohl(ihp[4]); + ih->isa_msgid = ntohl(ih->isa_msgid); + ih->isa_length = ntohl(ih->isa_length); +} + + +/* + * send an IKE ping + * + */ +static void +send_ping(int afamily, + int s, + ip_address *raddr, + int rport) +{ + struct isakmp_hdr ih; + int i, raddrlen; + + raddrlen=0; + + for(i=0; i<COOKIE_SIZE; i++) { + ih.isa_icookie[i]=rand()&0xff; + } + + for(i=0; i<COOKIE_SIZE; i++) { + ih.isa_rcookie[i]=rand()&0xff; + } + + ih.isa_np = NOTHING_WRONG; + ih.isa_version = (1 << ISA_MAJ_SHIFT) | 0; + ih.isa_xchg = (exchange_number ? + exchange_number : ISAKMP_XCHG_ECHOREQUEST_PRIV); + ih.isa_flags =0; + ih.isa_msgid =rand(); + ih.isa_length=0; + + switch(afamily) { + case AF_INET: + raddr->u.v4.sin_port = htons(rport); + raddrlen=sizeof(raddr->u.v4); + break; + + case AF_INET6: + raddr->u.v6.sin6_port = htons(rport); + raddrlen=sizeof(raddr->u.v6); + break; + } + + hton_ping(&ih); + + if(sendto(s, &ih, sizeof(ih), 0, (struct sockaddr *)raddr, raddrlen) < 0) { + perror("sendto"); + exit(5); + } +} + +/* + * send an IKE ping + * + */ +static void +reply_packet(int afamily, + int s, + ip_address *dst_addr, + int dst_len, + struct isakmp_hdr *op) +{ + int i, tmp; + + tmp=afamily; /* shut up compiler */ + + for(i=0; i<COOKIE_SIZE; i++) { + tmp=op->isa_icookie[i]; + op->isa_icookie[i]=op->isa_rcookie[i]; + op->isa_rcookie[i]=tmp; + } + + op->isa_np = NOTHING_WRONG; + op->isa_version = (1 << ISA_MAJ_SHIFT) | 0; + op->isa_xchg = ISAKMP_XCHG_ECHOREPLY; + op->isa_flags =0; + op->isa_msgid =rand(); + op->isa_length=0; + + hton_ping(op); + + if(sendto(s, op, sizeof(*op), 0, (struct sockaddr *)dst_addr, dst_len) < 0) { + perror("sendto"); + exit(5); + } +} + +/* + * receive and decode packet. + * + */ +static void +receive_ping(int afamily, int s, int reply) +{ + ip_address sender; + struct isakmp_hdr ih; + char buf[64]; + int n, rport, sendlen; + const char *xchg_name; + int xchg; + + rport = 500; + xchg = 0; + sendlen=sizeof(sender); + n = recvfrom(s, &ih, sizeof(ih), 0, (struct sockaddr *)&sender, &sendlen); + + addrtot(&sender, 0, buf, sizeof(buf)); + switch(afamily) { + case AF_INET: + rport = sender.u.v4.sin_port; + break; + + case AF_INET6: + rport = sender.u.v6.sin6_port; + break; + } + + if((unsigned int)n < sizeof(ih)) { + fprintf(stderr, "read short packet (%d) from %s/%d\n", + n, buf, rport); + return; + } + + /* translate from network byte order */ + ntoh_ping(&ih); + + + if(ih.isa_xchg == ISAKMP_XCHG_ECHOREQUEST || + ih.isa_xchg == ISAKMP_XCHG_ECHOREQUEST_PRIV || + (exchange_number!=0 && ih.isa_xchg == exchange_number)) { + xchg_name="echo-request"; + xchg=ISAKMP_XCHG_ECHOREQUEST; + } else if(ih.isa_xchg == ISAKMP_XCHG_ECHOREPLY || + ih.isa_xchg == ISAKMP_XCHG_ECHOREPLY_PRIV || + (exchange_number!=0 && ih.isa_xchg == exchange_number+1)) { + xchg_name="echo-reply"; + } else { + xchg_name=""; + } + + printf("received %d(%s) packet from %s/%d of len: %d\n", + ih.isa_xchg, xchg_name, buf, ntohs(rport), n); + printf("\trcookie=%08x_%08x icookie=%08x_%08x msgid=%08x\n", + *(u_int32_t *)(ih.isa_icookie), + *(u_int32_t *)(ih.isa_icookie+4), + *(u_int32_t *)(ih.isa_rcookie), + *(u_int32_t *)(ih.isa_rcookie+4), + ih.isa_msgid); + printf("\tnp=%03d version=%d.%d xchg=%s(%d)\n", + ih.isa_np, + ih.isa_version >> ISA_MAJ_SHIFT, + ih.isa_version & ISA_MIN_MASK, + xchg_name, + ih.isa_xchg); + + if(reply && xchg==ISAKMP_XCHG_ECHOREQUEST) { + reply_packet(afamily, s, &sender, sendlen, &ih); + } +} + +static const struct option long_opts[] = { + /* name, has_arg, flag, val */ + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "listen", no_argument, NULL, 's' }, + { "ikeport", required_argument, NULL, 'p' }, + { "ikeaddress", required_argument, NULL, 'b' }, + { "inet", no_argument, NULL, '4' }, + { "inet6", no_argument, NULL, '6' }, + { "exchangenum", required_argument, NULL, 'n' }, + { "wait", required_argument, NULL, 'w' }, + { 0,0,0,0 } +}; + +int +main(int argc, char **argv) +{ + char *foo; + const char *errstr; + int s; + int listen_only; + int lport,dport; + int afamily; + int pfamily; + int c; + int numSenders, numReceived, noDNS; + int waitTime; + int verbose, timedOut; + ip_address laddr, raddr; + + afamily=AF_INET; + pfamily=PF_INET; + lport=500; + dport=500; + waitTime=10; + verbose=0; + listen_only=0; + noDNS=0; + bzero(&laddr, sizeof(laddr)); + + while((c = getopt_long(argc, argv, "hVnvsp:b:46E:w:", long_opts, 0))!=EOF) { + switch (c) { + case 'h': /* --help */ + help(); + return 0; /* GNU coding standards say to stop here */ + + case 'V': /* --version */ + fprintf(stderr, "FreeS/WAN %s\n", ipsec_version_code()); + return 0; /* GNU coding standards say to stop here */ + + case 'v': /* --label <string> */ + verbose++; + continue; + + case 'n': + noDNS=1; + break; + + case 'E': + exchange_number=strtol(optarg, &foo, 0); + if(optarg==foo || exchange_number < 1 || exchange_number>255) { + fprintf(stderr, "Invalid exchange number '%s' (should be 1<=x<255)\n", + optarg); + exit(1); + } + continue; + + + case 's': + listen_only++; + continue; + + case 'p': + lport=strtol(optarg, &foo, 0); + if(optarg==foo || lport <0 || lport>65535) { + fprintf(stderr, "Invalid port number '%s' (should be 0<=x<65536)\n", + optarg); + exit(1); + } + continue; + + case 'w': + waitTime=strtol(optarg, &foo, 0); + if(optarg==foo || waitTime < 0) { + fprintf(stderr, "Invalid waittime number '%s' (should be 0<=x)\n", + optarg); + exit(1); + } + continue; + + case 'b': + errstr = ttoaddr(optarg, strlen(optarg), afamily, &laddr); + if(errstr!=NULL) { + fprintf(stderr, "Invalid local address '%s': %s\n", + optarg, errstr); + exit(1); + } + continue; + + case '4': + afamily=AF_INET; + pfamily=PF_INET; + continue; + + case '6': + afamily=AF_INET6; + pfamily=PF_INET6; + continue; + + default: + assert(FALSE); /* unknown return value */ + } + } + + s=socket(pfamily, SOCK_DGRAM, IPPROTO_UDP); + if(s < 0) { + perror("socket"); + exit(3); + } + + switch(afamily) { + case AF_INET: + laddr.u.v4.sin_port = htons(lport); + if(bind(s, (struct sockaddr *)&laddr.u.v4, sizeof(laddr.u.v4)) < 0) { + perror("v4 bind"); + exit(5); + } + break; + + case AF_INET6: + laddr.u.v6.sin6_port = htons(lport); + if(bind(s, (struct sockaddr *)&laddr.u.v6, sizeof(laddr.u.v6)) < 0) { + perror("v6 bind"); + exit(5); + } + break; + } + + numSenders = 0; + + if(!listen_only) { + while(optind < argc) { + char *port; + char *host; + char namebuf[128]; + + host = argv[optind]; + + port = strchr(host, '/'); + dport=500; + if(port) { + *port='\0'; + port++; + dport= strtol(port, &foo, 0); + if(port==foo || dport < 0 || dport > 65535) { + fprintf(stderr, "Invalid port number '%s' " + "(should be 0<=x<65536)\n", + port); + exit(1); + } + } + + errstr = ttoaddr(host, strlen(host), + afamily, &raddr); + if(errstr!=NULL) { + fprintf(stderr, "Invalid remote address '%s': %s\n", + host, errstr); + exit(1); + } + + addrtot(&raddr, 0, namebuf, sizeof(namebuf)); + + printf("Sending packet to %s/%d\n", namebuf, dport); + + send_ping(afamily, s, &raddr, dport); + numSenders++; + optind++; + } + } + + timedOut = 0; + numReceived=0; + + /* really should catch ^C and print stats on exit */ + while(numSenders > 0 || listen_only) { + struct pollfd ready; + int n; + + ready.fd = s; + ready.events = POLLIN; + + n = poll(&ready, 1, waitTime); + if(n < 0) { + perror("poll"); + exit(1); + } + + if(n == 0 && !listen_only) { + break; + } + + if(n == 1) { + numReceived++; + receive_ping(afamily, s, listen_only); + } + } + + if(numReceived > 0) { + printf("%d packets sent, %d packets received. %d packet loss\n", + numSenders, numReceived, numSenders*100/numReceived); + } + exit(0); +} + +/* + * Local variables: + * c-file-style: "linux" + * c-basic-offset: 4 + * End: + * + */ |