diff options
Diffstat (limited to 'programs/pf_key/pf_key.c')
-rw-r--r-- | programs/pf_key/pf_key.c | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/programs/pf_key/pf_key.c b/programs/pf_key/pf_key.c new file mode 100644 index 000000000..af7365d65 --- /dev/null +++ b/programs/pf_key/pf_key.c @@ -0,0 +1,353 @@ +/* + * @(#) pfkey socket manipulator/observer + * + * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org> + * and Michael Richardson <mcr@freeswan.org> + * + * 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: pf_key.c,v 1.2 2004/04/20 21:23:25 as Exp $ + * + */ + +/* + * This program opens a pfkey socket and prints all messages that it sees. + * + * This can be used to diagnose problems. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <errno.h> +#include <setjmp.h> +#include <signal.h> + +#include <sys/socket.h> + +#include <sys/types.h> +#include <stdint.h> +#include <freeswan.h> +#include <pfkeyv2.h> +#include <pfkey.h> + +char *progname; +uint32_t pfkey_seq = 0; +int pfkey_sock; + +static void +Usage(char *progname) +{ + fprintf(stderr, "%s: Usage: %s [--help]\n" + "\tby default listens for AH, ESP, IPIP and IPCOMP\n" + "\t--daemon <file> fork before printing, stuffing the PID in the file\n" + "\t--ah listen for AH messages\n" + "\t--esp listen for ESP messages\n" + "\t--ipip listen for IPIP messages\n" + "\t--ipcomp listen for IPCOMP messages\n", + progname, progname); + exit(1); +} + +void +pfkey_register(uint8_t satype) { + /* for registering SA types that can be negotiated */ + int error = 0; + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + struct sadb_msg *pfkey_msg; + + pfkey_extensions_init(extensions); + if((error = pfkey_msg_hdr_build(&extensions[0], + SADB_REGISTER, + satype, + 0, + ++pfkey_seq, + getpid()))) { + fprintf(stderr, "%s: Trouble building message header, error=%d.\n", + progname, error); + pfkey_extensions_free(extensions); + exit(1); + } + if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) { + fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n", + progname, error); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + exit(1); + } + if(write(pfkey_sock, pfkey_msg, + pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) != + (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) { + /* cleanup code here */ + fprintf(stderr, "%s: Trouble writing to channel PF_KEY.\n", progname); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + exit(1); + } + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); +} + +int dienow; + +void controlC(int foo) +{ + fflush(stdout); + printf("%s: Exiting on signal 15\n", progname); + fflush(stderr); + exit(0); +} + +int +main(int argc, char *argv[]) +{ + int opt; + ssize_t readlen; + unsigned char pfkey_buf[256]; + struct sadb_msg *msg; + int fork_after_register; + char *pidfilename; + + static int ah_register; + static int esp_register; + static int ipip_register; + static int ipcomp_register; + + static struct option long_options[] = + { + {"help", no_argument, 0, 'h'}, + {"daemon", required_argument, 0, 'f'}, + {"ah", no_argument, &ah_register, 1}, + {"esp", no_argument, &esp_register, 1}, + {"ipip", no_argument, &ipip_register, 1}, + {"ipcomp", no_argument, &ipcomp_register, 1}, + }; + + ah_register = 0; + esp_register = 0; + ipip_register = 0; + ipcomp_register=0; + dienow = 0; + fork_after_register=0; + pidfilename=NULL; + + progname = argv[0]; + if(strrchr(progname, '/')) { + progname=strrchr(progname, '/')+1; + } + + while((opt = getopt_long(argc, argv, "hf:", + long_options, NULL)) != EOF) { + switch(opt) { + case 'f': + pidfilename=optarg; + fork_after_register=1; + break; + case 'h': + Usage(progname); + break; + case '0': + /* it was a long option with a flag */ + break; + } + } + + if((pfkey_sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2) ) < 0) { + fprintf(stderr, "%s: failed to open PF_KEY family socket: %s\n", + progname, strerror(errno)); + exit(1); + } + + if(ah_register == 0 && + esp_register== 0 && + ipip_register==0 && + ipcomp_register==0) { + ah_register=1; + esp_register=1; + ipip_register=1; + ipcomp_register=1; + } + + if(ah_register) { + pfkey_register(SADB_SATYPE_AH); + } + if(esp_register) { + pfkey_register(SADB_SATYPE_ESP); + } + if(ipip_register) { + pfkey_register(SADB_X_SATYPE_IPIP); + } + if(ipcomp_register) { + pfkey_register(SADB_X_SATYPE_COMP); + } + + if(fork_after_register) { + /* + * to aid in regression testing, we offer to register + * everything first, and then we fork. As part of this + * we write the PID of the new process to a file + * provided. + */ + int pid; + FILE *pidfile; + + fflush(stdout); + fflush(stderr); + + pid=fork(); + if(pid!=0) { + /* in parent! */ + exit(0); + } + + if((pidfile=fopen(pidfilename, "w"))==NULL) { + perror(pidfilename); + } else { + fprintf(pidfile, "%d", getpid()); + fclose(pidfile); + } + } + + signal(SIGINT, controlC); + signal(SIGTERM, controlC); + + while((readlen = read(pfkey_sock, pfkey_buf, sizeof(pfkey_buf))) > 0) { + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + msg = (struct sadb_msg *)pfkey_buf; + + /* first, see if we got enough for an sadb_msg */ + if((size_t)readlen < sizeof(struct sadb_msg)) { + printf("%s: runt packet of size: %d (<%lu)\n", + progname, (int)readlen, (unsigned long)sizeof(struct sadb_msg)); + continue; + } + + /* okay, we got enough for a message, print it out */ + printf("\npfkey v%d msg. type=%d(%s) seq=%d len=%d pid=%d errno=%d satype=%d(%s)\n", + msg->sadb_msg_version, + msg->sadb_msg_type, + pfkey_v2_sadb_type_string(msg->sadb_msg_type), + msg->sadb_msg_seq, + msg->sadb_msg_len, + msg->sadb_msg_pid, + msg->sadb_msg_errno, + msg->sadb_msg_satype, + satype2name(msg->sadb_msg_satype)); + + if((size_t)readlen != msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) + { + printf("%s: packet size read from socket=%d doesn't equal sadb_msg_len %d * %u; message not decoded\n", + progname, + (int)readlen, + msg->sadb_msg_len, + (int) IPSEC_PFKEYv2_ALIGN); + continue; + } + + pfkey_lib_debug = PF_KEY_DEBUG_PARSE_STRUCT; + if (pfkey_msg_parse(msg, NULL, extensions, EXT_BITS_OUT)) { + printf("%s: unparseable PF_KEY message.\n", + progname); + } else { + printf("%s: parseable PF_KEY message.\n", + progname); + } + } + printf("%s: exited normally\n", progname); + exit(0); +} + +/* + * $Log: pf_key.c,v $ + * Revision 1.2 2004/04/20 21:23:25 as + * int cast fix for 64 bit platforms + * + * Revision 1.1 2004/03/15 20:35:28 as + * added files from freeswan-2.04-x509-1.5.3 + * + * Revision 1.15 2003/09/10 00:01:30 mcr + * fixes for gcc 3.3 from Matthias Bethke <Matthias.Bethke@gmx.net> + * + * Revision 1.14 2002/10/09 03:12:05 dhr + * + * [kenb+dhr] 64-bit fixes + * + * Revision 1.13 2002/09/20 05:02:15 rgb + * Cleaned up pfkey_lib_debug usage. + * + * Revision 1.12 2002/09/13 23:02:23 rgb + * Type fiddling to tame ia64 compiler. + * Added text labels to elucidate numeric values presented. + * + * Revision 1.11 2002/08/26 03:05:25 mcr + * duh, pf_key much catch SIGTERM as well as SIGINT... + * + * Revision 1.10 2002/08/13 19:01:27 mcr + * patches from kenb to permit compilation of FreeSWAN on ia64. + * des library patched to use proper DES_LONG type for ia64. + * + * Revision 1.9 2002/07/16 02:53:42 mcr + * added --daemon <pidfile> to "ipsec pf_key" command. + * this is used in *-trap-* tests to avoid race conditions between + * registration of PF_KEY listeners and arrival of first test packet. + * + * Revision 1.8 2002/06/17 04:32:55 mcr + * exit nicely from pf_key when SIGINT (^C) is sent. + * This is needed so that the stdout will flush properly. + * + * Revision 1.7 2002/04/24 07:55:32 mcr + * #include patches and Makefiles for post-reorg compilation. + * + * Revision 1.6 2002/04/24 07:35:39 mcr + * Moved from ./klips/utils/pf_key.c,v + * + * Revision 1.5 2002/03/08 21:44:04 rgb + * Update for all GNU-compliant --version strings. + * + * Revision 1.4 2001/11/27 05:19:06 mcr + * added extra newline between packets. + * set pfkey_lib_debug to enum rather than just to "1". + * + * Revision 1.3 2001/11/27 03:35:29 rgb + * Added stdlib *again*. + * + * Revision 1.2 2001/11/23 07:23:14 mcr + * pulled up klips2 Makefile and pf_key code. + * + * Revision 1.1.2.5 2001/10/23 18:49:12 mcr + * renamed man page to section 8. + * added --ah, --esp, --ipcomp and --ipip to control which + * protocols are printed. + * incomplete messages which include at least an sadb header are printed. + * + * Revision 1.1.2.4 2001/10/22 21:50:51 rgb + * Added pfkey register for AH, ESP, IPIP and COMP. + * + * Revision 1.1.2.3 2001/10/21 21:51:06 rgb + * Bug fixes to get working. + * + * Revision 1.1.2.2 2001/10/20 22:45:31 rgb + * Added check for exact length and a call to message parser to get some + * idea of the contents of each extension. + * + * Revision 1.1.2.1 2001/10/17 23:25:37 mcr + * added "pk_key" program to dump raw kernel pf messages. + * (program is still skeletal) + * + * + * Local variables: + * c-file-style: "linux" + * End: + * + */ |