diff options
Diffstat (limited to 'programs/spi')
-rw-r--r-- | programs/spi/.cvsignore | 1 | ||||
-rw-r--r-- | programs/spi/Makefile | 69 | ||||
-rw-r--r-- | programs/spi/spi.5 | 213 | ||||
-rw-r--r-- | programs/spi/spi.8 | 525 | ||||
-rw-r--r-- | programs/spi/spi.c | 1689 |
5 files changed, 2497 insertions, 0 deletions
diff --git a/programs/spi/.cvsignore b/programs/spi/.cvsignore new file mode 100644 index 000000000..c928c4b77 --- /dev/null +++ b/programs/spi/.cvsignore @@ -0,0 +1 @@ +spi diff --git a/programs/spi/Makefile b/programs/spi/Makefile new file mode 100644 index 000000000..10a1eaa9c --- /dev/null +++ b/programs/spi/Makefile @@ -0,0 +1,69 @@ +# 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.2 2004/03/22 21:53:21 as Exp $ + +FREESWANSRCDIR=../.. +include ${FREESWANSRCDIR}/Makefile.inc + +PROGRAM=spi +EXTRA5PROC=${PROGRAM}.5 + +LIBS=${FREESWANLIB} + +OBJS=constants.o alg_info.o kernel_alg.o + +include ../Makefile.program + +constants.o : ../pluto/constants.c ../pluto/constants.h + $(CC) $(CFLAGS) -c -o $@ $< + +alg_info.o : ../pluto/alg_info.c ../pluto/alg_info.h + $(CC) $(CFLAGS) -DNO_PLUTO -c -o $@ $< + +kernel_alg.o : ../pluto/kernel_alg.c ../pluto/kernel_alg.h + $(CC) $(CFLAGS) -DNO_PLUTO -c -o $@ $< + +# +# $Log: Makefile,v $ +# Revision 1.2 2004/03/22 21:53:21 as +# merged alg-0.8.1 branch with HEAD +# +# Revision 1.1.4.1 2004/03/16 09:48:22 as +# alg-0.8.1rc12 patch merged +# +# Revision 1.1 2004/03/15 20:35:31 as +# added files from freeswan-2.04-x509-1.5.3 +# +# Revision 1.4 2002/06/03 20:25:31 mcr +# man page for files actually existant in /proc/net changed back to +# ipsec_foo via new EXTRA5PROC process. +# +# Revision 1.3 2002/06/02 21:51:41 mcr +# changed TOPDIR->FREESWANSRCDIR in all Makefiles. +# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the +# kernel sense.) +# +# Revision 1.2 2002/04/26 01:21:26 mcr +# while tracking down a missing (not installed) /etc/ipsec.conf, +# MCR has decided that it is not okay for each program subdir to have +# some subset (determined with -f) of possible files. +# Each subdir that defines $PROGRAM, MUST have a PROGRAM.8 file as well as a PROGRAM file. +# Optional PROGRAM.5 files have been added to the makefiles. +# +# Revision 1.1 2002/04/24 07:55:32 mcr +# #include patches and Makefiles for post-reorg compilation. +# +# +# diff --git a/programs/spi/spi.5 b/programs/spi/spi.5 new file mode 100644 index 000000000..a8faebee4 --- /dev/null +++ b/programs/spi/spi.5 @@ -0,0 +1,213 @@ +.TH IPSEC_SPI 5 "26 Jun 2000" +.\" +.\" RCSID $Id: spi.5,v 1.1 2004/03/15 20:35:31 as Exp $ +.\" +.SH NAME +ipsec_spi \- list IPSEC Security Associations +.SH SYNOPSIS +.B ipsec +.B spi +.PP +.B cat +.B /proc/net/ipsec_spi +.PP +.SH DESCRIPTION +.I /proc/net/ipsec_spi +is a read-only file that lists the current IPSEC Security Associations. +A Security Association (SA) is a transform through which packet contents +are to be processed before being forwarded. A transform can be an +IPv4-in-IPv4 or IPv6-in-IPv6 encapsulation, an IPSEC Authentication Header (authentication +with no encryption), or an IPSEC Encapsulation Security Payload +(encryption, possibly including authentication). +.PP +When a packet is passed from a higher networking layer through an IPSEC +virtual interface, a search in the extended routing table (see +.IR ipsec_eroute (5)) +yields +a IP protocol number +, +a Security Parameters Index (SPI) +and +an effective destination address +. +When an IPSEC packet arrives from the network, +its ostensible destination, an SPI and an IP protocol +specified by its outermost IPSEC header are used. +The destination/SPI/protocol combination is used to select a relevant SA. +(See +.IR ipsec_spigrp (5) +for discussion of how multiple transforms are combined.) +.PP +An +.I spi , +.I proto, +.I daddr +and +.IR address_family +arguments specify an SAID. +.I Proto +is an ASCII string, "ah", "esp", "comp" or "tun", specifying the IP protocol. +.I Spi +is a number, preceded by '.' indicating hexadecimal and IPv4 or by ':' indicating hexadecimal and IPv6, +where each hexadecimal digit represents 4 bits, +between +.B 0x100 +and +.BR 0xffffffff ; +values from +.B 0x0 +to +.B 0xff +are reserved. +.I Daddr +is a dotted-decimal IPv4 destination address or a coloned hex IPv6 destination address. +.PP +An +.I SAID +combines the three parameters above, such as: "tun.101@1.2.3.4" for IPv4 or "tun:101@3049:1::1" for IPv6 +.PP +A table entry consists of: +.IP + 3 +.BR SAID +.IP + +<transform name (proto,encalg,authalg)>: +.IP + +direction (dir=) +.IP + +source address (src=) +.IP + +source and destination addresses and masks for inner header policy check +addresses (policy=), as dotted-quads or coloned hex, separated by '->', +for IPv4-in-IPv4 or IPv6-in-IPv6 SAs only +.IP + +initialisation vector length and value (iv_bits=, iv=) if non-zero +.IP + +out-of-order window size, number of out-of-order errors, sequence +number, recently received packet bitmask, maximum difference between +sequence numbers (ooowin=, ooo_errs=, seq=, bit=, max_seq_diff=) if SA +is AH or ESP and if individual items are non-zero +.IP + +extra flags (flags=) if any are set +.IP + +authenticator length in bits (alen=) if non-zero +.IP + +authentication key length in bits (aklen=) if non-zero +.IP + +authentication errors (auth_errs=) if non-zero +.IP + +encryption key length in bits (eklen=) if non-zero +.IP + +encryption size errors (encr_size_errs=) if non-zero +.IP + +encryption padding error warnings (encr_pad_errs=) if non-zero +.IP + +lifetimes legend, c=Current status, s=Soft limit when exceeded will +initiate rekeying, h=Hard limit will cause termination of SA (life(c,s,h)=) +.IP + 6 +number of connections to which the SA is allocated (c), that will cause a +rekey (s), that will cause an expiry (h) (alloc=), if any value is non-zero +.IP + +number of bytes processesd by this SA (c), that will cause a rekey (s), that +will cause an expiry (h) (bytes=), if any value is non-zero +.IP + +time since the SA was added (c), until rekey (s), until expiry (h), in seconds (add=) +.IP + +time since the SA was first used (c), until rekey (s), until expiry (h), in seconds (used=), +if any value is non-zero +.IP + +number of packets processesd by this SA (c), that will cause a rekey (s), that +will cause an expiry (h) (packets=), if any value is non-zero +.IP + 3 +time since the last packet was processed, in seconds (idle=), if SA has +been used +.IP +average compression ratio (ratio=) +.SH EXAMPLES +.B "tun.12a@192.168.43.1 IPIP: dir=out src=192.168.43.2" +.br +.B " life(c,s,h)=bytes(14073,0,0)add(269,0,0)" +.br +.B " use(149,0,0)packets(14,0,0)" +.br +.B " idle=23 +.LP +is an outbound IPv4-in-IPv4 (protocol 4) tunnel-mode SA set up between machines +192.168.43.2 and 192.168.43.1 with an SPI of 12a in hexadecimal that has +passed about 14 kilobytes of traffic in 14 packets since it was created, +269 seconds ago, first used 149 seconds ago and has been idle for 23 +seconds. +.LP +.B "esp:9a35fc02@3049:1::1 ESP_3DES_HMAC_MD5:" +.br +.B " dir=in src=9a35fc02@3049:1::2" +.br +.B " ooowin=32 seq=7149 bit=0xffffffff" +.br +.B " alen=128 aklen=128 eklen=192" +.br +.B " life(c,s,h)=bytes(1222304,0,0)add(4593,0,0)" +.br +.B " use(3858,0,0)packets(7149,0,0)" +.br +.B " idle=23" +.LP +is an inbound Encapsulating Security Payload (protocol 50) SA on machine +3049:1::1 with an SPI of 9a35fc02 that uses 3DES as the encryption +cipher, HMAC MD5 as the authentication algorithm, an out-of-order +window of 32 packets, a present sequence number of 7149, every one of +the last 32 sequence numbers was received, the authenticator length and +keys is 128 bits, the encryption key is 192 bits (actually 168 for 3DES +since 1 of 8 bits is a parity bit), has passed 1.2 Mbytes of data in +7149 packets, was added 4593 seconds ago, first used +3858 seconds ago and has been idle for 23 seconds. +.LP +.SH FILES +/proc/net/ipsec_spi, /usr/local/bin/ipsec +.SH "SEE ALSO" +ipsec(8), ipsec_manual(8), ipsec_tncfg(5), ipsec_eroute(5), +ipsec_spigrp(5), ipsec_klipsdebug(5), ipsec_spi(8), ipsec_version(5), +ipsec_pf_key(5) +.SH HISTORY +Written for the Linux FreeS/WAN project +<http://www.freeswan.org/> +by Richard Guy Briggs. +.SH BUGS +The add and use times are awkward, displayed in seconds since machine +start. It would be better to display them in seconds before now for +human readability. +.\" +.\" $Log: spi.5,v $ +.\" Revision 1.1 2004/03/15 20:35:31 as +.\" added files from freeswan-2.04-x509-1.5.3 +.\" +.\" Revision 1.9 2002/04/24 07:35:39 mcr +.\" Moved from ./klips/utils/spi.5,v +.\" +.\" Revision 1.8 2001/08/01 23:22:44 rgb +.\" Fix inconsistancies between manpage and output. +.\" +.\" Revision 1.7 2000/11/30 16:47:28 rgb +.\" Added src= to /proc/net/ipsec_spi manpage. +.\" +.\" Revision 1.6 2000/09/17 18:56:48 rgb +.\" Added IPCOMP support. +.\" +.\" Revision 1.5 2000/09/13 15:54:32 rgb +.\" Added Gerhard's ipv6 updates. +.\" +.\" Revision 1.4 2000/07/05 17:24:03 rgb +.\" Updated for relative, rather than absolute values for addtime and +.\" usetime. +.\" +.\" Revision 1.3 2000/06/30 18:21:55 rgb +.\" Update SEE ALSO sections to include ipsec_version(5) and ipsec_pf_key(5) +.\" and correct FILES sections to no longer refer to /dev/ipsec which has +.\" been removed since PF_KEY does not use it. +.\" +.\" Revision 1.2 2000/06/28 12:44:12 henry +.\" format touchup +.\" +.\" Revision 1.1 2000/06/28 05:43:00 rgb +.\" Added manpages for all 5 klips utils. +.\" +.\" diff --git a/programs/spi/spi.8 b/programs/spi/spi.8 new file mode 100644 index 000000000..fe6537c07 --- /dev/null +++ b/programs/spi/spi.8 @@ -0,0 +1,525 @@ +.TH IPSEC_SPI 8 "23 Oct 2001" +.\" +.\" RCSID $Id: spi.8,v 1.1 2004/03/15 20:35:31 as Exp $ +.\" +.SH NAME +ipsec spi \- manage IPSEC Security Associations +.SH SYNOPSIS +.br +Note: In the following, +.br +.B <SA> +means: +.B \-\-af +(inet | inet6) +.B \-\-edst +daddr +.B \-\-spi +spi +.B \-\-proto +proto OR +.B \-\-said +said, +.br +.B <life> +means: +.B \-\-life +(soft | hard)\-(allocations | bytes | addtime | usetime | packets)=value[,...] +.PP +.B ipsec +.B spi +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-src +src +.B \-\-ah +.BR hmac-md5-96 | hmac-sha1-96 +[ +.B \-\-replay_window +replayw ] +[ +.B <life> +] +.B \-\-authkey +akey +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-src +src +.B \-\-esp +.BR 3des +[ +.B \-\-replay_window +replayw ] +[ +.B <life> +] +.B \-\-enckey +ekey +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-src +src +.B \-\-esp +.BR 3des-md5-96 | 3des-sha1-96 +[ +.B \-\-replay_window +replayw ] +[ +.B <life> +] +.B \-\-enckey +ekey +.B \-\-authkey +akey +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-src +src +.B \-\-comp +.BR deflate +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-ip4 +.B \-\-src +encap-src +.B \-\-dst +encap-dst +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-ip6 +.B \-\-src +encap-src +.B \-\-dst +encap-dst +.PP +.B ipsec +.B spi +.B <SA> +.B \-\-del +.PP +.B ipsec +.B spi +.B \-\-help +.PP +.B ipsec +.B spi +.B \-\-version +.PP +.B ipsec +.B spi +.B \-\-clear +.PP +.SH DESCRIPTION +.I Spi +creates and deletes IPSEC Security Associations. +A Security Association (SA) is a transform through which packet +contents are to be processed before being forwarded. +A transform can be an IPv4-in-IPv4 or an IPv6-in-IPv6 encapsulation, +an IPSEC Authentication Header (authentication with no encryption), +or an IPSEC Encapsulation Security Payload (encryption, possibly +including authentication). +.PP +When a packet is passed from a higher networking layer +through an IPSEC virtual interface, +a search in the extended routing table (see +.IR ipsec_eroute (8)) +yields an effective destination address, a +Security Parameters Index (SPI) and a IP protocol number. +When an IPSEC packet arrives from the network, +its ostensible destination, an SPI and an IP protocol +specified by its outermost IPSEC header are used. +The destination/SPI/protocol combination is used to select a relevant SA. +(See +.IR ipsec_spigrp (8) +for discussion of how multiple transforms are combined.) +.PP +The +.IR af , +.IR daddr , +.I spi +and +.I proto +arguments specify the SA to be created or deleted. +.I af +is the address family (inet for IPv4, inet6 for IPv6). +.I Daddr +is a destination address +in dotted-decimal notation for IPv4 +or in a coloned hex notation for IPv6. +.I Spi +is a number, preceded by '0x' for hexadecimal, +between +.B 0x100 +and +.BR 0xffffffff ; +values from +.B 0x0 +to +.B 0xff +are reserved. +.I Proto +is an ASCII string, "ah", "esp", "comp" or "tun", specifying the IP protocol. +The protocol must agree with the algorithm selected. +.PP +Alternatively, the +.I said +argument can also specify an SA to be created or deleted. +.I Said +combines the three parameters above, such as: "tun.101@1.2.3.4" or "tun:101@1:2::3:4", +where the address family is specified by "." for IPv4 and ":" for IPv6. The address +family indicators substitute the "0x" for hexadecimal. +.PP +The source address, +.IR src , +must also be provided for the inbound policy check to +function. The source address does not need to be included if inbound +policy checking has been disabled. +.PP +Keys vectors must be entered as hexadecimal or base64 numbers. +They should be cryptographically strong random numbers. +.PP +All hexadecimal numbers are entered as strings of hexadecimal digits +(0-9 and a-f), without spaces, preceded by '0x', where each hexadecimal +digit represents 4 bits. +All base64 numbers are entered as strings of base64 digits + (0-9, A-Z, a-z, '+' and '/'), without spaces, preceded by '0s', +where each hexadecimal digit represents 6 bits and '=' is used for padding. +.PP +The deletion of an SA which has been grouped will result in the entire chain +being deleted. +.PP +The form with no additional arguments lists the contents of +/proc/net/ipsec_spi. The format of /proc/net/ipsec_spi is discussed in +ipsec_spi(5). +.PP +The lifetime severity of +.B soft +sets a limit when the key management daemons are asked to rekey the SA. +The lifetime severity of +.B hard +sets a limit when the SA must expire. +The lifetime type +.B allocations +tells the system when to expire the SA because it is being shared by too many +eroutes (not currently used). The lifetime type of +.B bytes +tells the system to expire the SA after a certain number of bytes have been +processed with that SA. The lifetime type of +.B addtime +tells the system to expire the SA a certain number of seconds after the SA was +installed. The lifetime type of +.B usetime +tells the system to expire the SA a certain number of seconds after that SA has +processed its first packet. The lifetime type of +.B packets +tells the system to expire the SA after a certain number of packets have been +processed with that SA. +.SH OPTIONS +.TP 10 +.B \-\-af +specifies the address family (inet for IPv4, inet6 for IPv6) +.TP +.B \-\-edst +specifies the effective destination +.I daddr +of the Security Association +.TP +.B \-\-spi +specifies the Security Parameters Index +.I spi +of the Security Association +.TP +.B \-\-proto +specifies the IP protocol +.I proto +of the Security Association +.TP +.B \-\-said +specifies the Security Association in monolithic format +.TP +.B \-\-ah +add an SA for an IPSEC Authentication Header, +specified by the following transform identifier +(\c +.BR hmac-md5-96 +or +.BR hmac-sha1-96 ) +(RFC2402, obsoletes RFC1826) +.TP +.B hmac-md5-96 +transform following the HMAC and MD5 standards, +using a 128-bit +.I key +to produce a 96-bit authenticator (RFC2403) +.TP +.B hmac-sha1-96 +transform following the HMAC and SHA1 standards, +using a 160-bit +.I key +to produce a 96-bit authenticator (RFC2404) +.TP +.B \-\-esp +add an SA for an IPSEC Encapsulation Security Payload, +specified by the following +transform identifier (\c +.BR 3des , +or +.BR 3des-md5-96 ) +(RFC2406, obsoletes RFC1827) +.TP +.B 3des +encryption transform following the Triple-DES standard in +Cipher-Block-Chaining mode using a 64-bit +.I iv +(internally generated) and a 192-bit 3DES +.I ekey +(RFC2451) +.TP +.B 3des-md5-96 +encryption transform following the Triple-DES standard in +Cipher-Block-Chaining mode with authentication provided by +HMAC and MD5 +(96-bit authenticator), +using a 64-bit +.IR iv +(internally generated), a 192-bit 3DES +.I ekey +and a 128-bit HMAC-MD5 +.I akey +(RFC2451, RFC2403) +.TP +.B 3des-sha1-96 +encryption transform following the Triple-DES standard in +Cipher-Block-Chaining mode with authentication provided by +HMAC and SHA1 +(96-bit authenticator), +using a 64-bit +.IR iv +(internally generated), a 192-bit 3DES +.I ekey +and a 160-bit HMAC-SHA1 +.I akey +(RFC2451, RFC2404) +.TP +.BR \-\-replay_window " replayw" +sets the replay window size; valid values are decimal, 1 to 64 +.TP +.BR \-\-life " life_param[,life_param]" +sets the lifetime expiry; the format of +.B life_param +consists of a comma-separated list of lifetime specifications without spaces; +a lifetime specification is comprised of a severity of +.BR soft " or " hard +followed by a '-', followed by a lifetime type of +.BR allocations ", " bytes ", " addtime ", " usetime " or " packets +followed by an '=' and finally by a value +.TP +.B \-\-comp +add an SA for IPSEC IP Compression, +specified by the following +transform identifier (\c +.BR deflate ) +(RFC2393) +.TP +.B deflate +compression transform following the patent-free Deflate compression algorithm +(RFC2394) +.TP +.B \-\-ip4 +add an SA for an IPv4-in-IPv4 +tunnel from +.I encap-src +to +.I encap-dst +.TP +.B \-\-ip6 +add an SA for an IPv6-in-IPv6 +tunnel from +.I encap-src +to +.I encap-dst +.TP +.B \-\-src +specify the source end of an IP-in-IP tunnel from +.I encap-src +to +.I encap-dst +and also specifies the source address of the Security Association to be +used in inbound policy checking and must be the same address +family as +.I af +and +.I edst +.TP +.B \-\-dst +specify the destination end of an IP-in-IP tunnel from +.I encap-src +to +.I encap-dst +.TP +.B \-\-del +delete the specified SA +.TP +.BR \-\-clear +clears the table of +.BR SA s +.TP +.BR \-\-help +display synopsis +.TP +.BR \-\-version +display version information +.SH EXAMPLES +To keep line lengths down and reduce clutter, +some of the long keys in these examples have been abbreviated +by replacing part of their text with +.RI `` ... ''. +Keys used when the programs are actually run must, +of course, be the full length required for the particular algorithm. +.LP +.B "ipsec spi \-\-af inet \-\-edst gw2 \-\-spi 0x125 \-\-proto esp \e" +.br +.B " \-\-src gw1 \e" +.br +.B " \-\-esp 3des\-md5\-96 \e" +.br +.BI "\ \ \ \-\-enckey\ 0x6630" "..." "97ce\ \e" +.br +.BI " \-\-authkey 0x9941" "..." "71df" +.LP +sets up an SA from +.BR gw1 +to +.BR gw2 +with an SPI of +.BR 0x125 +and protocol +.BR ESP +(50) using +.BR 3DES +encryption with integral +.BR MD5-96 +authentication transform, using an encryption key of +.BI 0x6630 ... 97ce +and an authentication key of +.BI 0x9941 ... 71df +(see note above about abbreviated keys). +.LP +.B "ipsec spi \-\-af inet6 \-\-edst 3049:9::9000:3100 \-\-spi 0x150 \-\-proto ah \e" +.br +.B " \-\-src 3049:9::9000:3101 \e" +.br +.B " \-\-ah hmac\-md5\-96 \e" +.br +.BI "\ \ \ \-\-authkey\ 0x1234" "..." "2eda\ \e" +.LP +sets up an SA from +.BR 3049:9::9000:3101 +to +.BR 3049:9::9000:3100 +with an SPI of +.BR 0x150 +and protocol +.BR AH +(50) using +.BR MD5-96 +authentication transform, using an authentication key of +.BI 0x1234 ... 2eda +(see note above about abbreviated keys). +.LP +.B "ipsec spi \-\-said tun.987@192.168.100.100 \-\-del " +.LP +deletes an SA to +.BR 192.168.100.100 +with an SPI of +.BR 0x987 +and protocol +.BR IPv4-in-IPv4 +(4). +.LP +.B "ipsec spi \-\-said tun:500@3049:9::1000:1 \-\-del " +.LP +deletes an SA to +.BR 3049:9::1000:1 +with an SPI of +.BR 0x500 +and protocol +.BR IPv6-in-IPv6 +(4). +.LP +.SH FILES +/proc/net/ipsec_spi, /usr/local/bin/ipsec +.SH "SEE ALSO" +ipsec(8), ipsec_manual(8), ipsec_tncfg(8), ipsec_eroute(8), +ipsec_spigrp(8), ipsec_klipsdebug(8), ipsec_spi(5) +.SH HISTORY +Written for the Linux FreeS/WAN project +<http://www.freeswan.org/> +by Richard Guy Briggs. +.SH BUGS +The syntax is messy and the transform naming needs work. +.\" +.\" $Log: spi.8,v $ +.\" Revision 1.1 2004/03/15 20:35:31 as +.\" added files from freeswan-2.04-x509-1.5.3 +.\" +.\" Revision 1.32 2002/04/24 07:35:40 mcr +.\" Moved from ./klips/utils/spi.8,v +.\" +.\" Revision 1.31 2001/11/06 20:18:47 rgb +.\" Added lifetime parameters. +.\" +.\" Revision 1.30 2001/10/24 03:23:32 rgb +.\" Added lifetime option and parameters. +.\" +.\" Revision 1.29 2001/05/30 08:14:04 rgb +.\" Removed vestiges of esp-null transforms. +.\" +.\" Revision 1.28 2000/11/29 19:15:20 rgb +.\" Add --src requirement for inbound policy routing. +.\" +.\" Revision 1.27 2000/09/17 18:56:48 rgb +.\" Added IPCOMP support. +.\" +.\" Revision 1.26 2000/09/13 15:54:32 rgb +.\" Added Gerhard's ipv6 updates. +.\" +.\" Revision 1.25 2000/09/12 22:36:45 rgb +.\" Gerhard's IPv6 support. +.\" +.\" Revision 1.24 2000/06/30 18:21:55 rgb +.\" Update SEE ALSO sections to include ipsec_version(5) and ipsec_pf_key(5) +.\" and correct FILES sections to no longer refer to /dev/ipsec which has +.\" been removed since PF_KEY does not use it. +.\" +.\" Revision 1.23 2000/06/21 16:54:57 rgb +.\" Added 'no additional args' text for listing contents of +.\" /proc/net/ipsec_* files. +.\" +.\" Revision 1.22 1999/08/11 08:35:16 rgb +.\" Update, deleting references to obsolete and insecure algorithms. +.\" +.\" Revision 1.21 1999/07/19 18:53:55 henry +.\" improve font usage in key abbreviations +.\" +.\" Revision 1.20 1999/07/19 18:50:09 henry +.\" fix slightly-misformed comments +.\" abbreviate long keys to avoid long-line complaints +.\" +.\" Revision 1.19 1999/04/06 04:54:38 rgb +.\" Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes +.\" patch shell fixes. +.\" diff --git a/programs/spi/spi.c b/programs/spi/spi.c new file mode 100644 index 000000000..369d556c7 --- /dev/null +++ b/programs/spi/spi.c @@ -0,0 +1,1689 @@ +/* + * All-in-one program to set Security Association parameters + * Copyright (C) 1996 John Ioannidis. + * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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. + */ + +char spi_c_version[] = "RCSID $Id: spi.c,v 1.7 2004/10/14 20:03:26 as Exp $"; + +#include <asm/types.h> +#include <sys/types.h> +#include <sys/ioctl.h> +/* #include <linux/netdevice.h> */ +#include <net/if.h> +/* #include <linux/types.h> */ /* new */ +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> + +/* #include <sys/socket.h> */ + +#include <netinet/in.h> +#include <arpa/inet.h> +/* #include <linux/ip.h> */ +#include <netdb.h> + +#include <unistd.h> +#include <getopt.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <freeswan.h> +#if 0 +#include <linux/autoconf.h> /* CONFIG_IPSEC_PFKEYv2 */ +#endif + #include <signal.h> + #include <sys/socket.h> + #include <pfkeyv2.h> + #include <pfkey.h> + +#include "freeswan/radij.h" +#include "freeswan/ipsec_encap.h" +#include "freeswan/ipsec_xform.h" +#include "freeswan/ipsec_ipe4.h" +#include "freeswan/ipsec_ah.h" +#include "freeswan/ipsec_esp.h" +#include "freeswan/ipsec_sa.h" /* IPSEC_SAREF_NULL */ + +/* + * Manual conn support for ipsec_alg (modular algos). + * Rather ugly to include from pluto dir but avoids + * code duplication. + */ +#ifndef NO_KERNEL_ALG +#include "../pluto/alg_info.h" +#include "../pluto/constants.h" +struct connection; +#include "../pluto/kernel_alg.h" +#endif /* NO_KERNEL_ALG */ + +char *program_name; +int debug = 0; +int saref = 0; +char *command; +extern char *optarg; +extern int optind, opterr, optopt; +char scratch[2]; +char *iv = NULL, *enckey = NULL, *authkey = NULL; +size_t ivlen = 0, enckeylen = 0, authkeylen = 0; +ip_address edst, dst, src; +int address_family = 0; +unsigned char proto = 0; +int alg = 0; + +#ifndef NO_KERNEL_ALG +/* + * Manual connection support for modular algos (ipsec_alg) --Juanjo. + */ +#define XF_OTHER_ALG (XF_CLR-1) /* define magic XF_ symbol for alg_info's */ +#include <assert.h> +const char *alg_string = NULL; /* algorithm string */ +struct alg_info_esp *alg_info = NULL; /* algorithm info got from string */ +struct esp_info *esp_info = NULL; /* esp info from 1st (only) element */ +const char *alg_err; /* auxiliar for parsing errors */ +int proc_read_ok = 0; /* /proc/net/pf_key_support read ok */ +#endif /* NO_KERNEL_ALG */ + +int replay_window = 0; +char sa[SATOT_BUF]; + +extern unsigned int pfkey_lib_debug; /* used by libfreeswan/pfkey_v2_build */ +int pfkey_sock; +fd_set pfkey_socks; +uint32_t pfkey_seq = 0; +enum life_severity { + life_soft = 0, + life_hard = 1, + life_maxsever = 2 +}; +enum life_type { + life_alloc = 0, + life_bytes = 1, + life_addtime = 2, + life_usetime = 3, + life_packets = 4, + life_maxtype = 5 +}; + +#define streql(_a,_b) (!strcmp((_a),(_b))) + +static const char *usage_string = "\ +Usage:\n\ + in the following, <SA> is: --af <inet | inet6> --edst <dstaddr> --spi <spi> --proto <proto>\n\ + OR: --said <proto><.|:><spi>@<dstaddr>\n\ + <life> is: --life <soft|hard>-<allocations|bytes|addtime|usetime|packets>=<value>[,...]\n\ +spi --clear\n\ +spi --help\n\ +spi --version\n\ +spi\n\ +spi --del <SA>\n\ +spi --ip4 <SA> --src <encap-src> --dst <encap-dst>\n\ +spi --ip6 <SA> --src <encap-src> --dst <encap-dst>\n\ +spi --ah <algo> <SA> [<life> ][ --replay_window <replay_window> ] --authkey <key>\n\ + where <algo> is one of: hmac-md5-96 | hmac-sha1-96\n\ +spi --esp <algo> <SA> [<life> ][ --replay_window <replay-window> ] --enckey <ekey> --authkey <akey>\n\ + where <algo> is one of: 3des-md5-96 | 3des-sha1-96\n\ +spi --esp <algo> <SA> [<life> ][ --replay_window <replay-window> ] --enckey <ekey>\n\ + where <algo> is: 3des\n\ +spi --comp <algo> <SA>\n\ + where <algo> is: deflate\n\ +[ --debug ] is optional to any spi command.\n\ +[ --label <label> ] is optional to any spi command.\n\ +[ --listenreply ] is optional, and causes the command to stick\n\ + around and listen to what the PF_KEY socket says.\n\ +"; + + +static void +usage(char *s, FILE *f) +{ + /* s argument is actually ignored, at present */ + fprintf(f, "%s:%s", s, usage_string); + exit(-1); +} + +int +parse_life_options(uint32_t life[life_maxsever][life_maxtype], + char *life_opt[life_maxsever][life_maxtype], + char *optarg) +{ + char *optargp = optarg; + char *endptr; + + do { + int life_severity, life_type; + char *optargt = optargp; + + if(strncmp(optargp, "soft", sizeof("soft")-1) == 0) { + life_severity = life_soft; + optargp += sizeof("soft")-1; + } else if(strncmp(optargp, "hard", sizeof("hard")-1) == 0) { + life_severity = life_hard; + optargp += sizeof("hard")-1; + } else { + fprintf(stderr, + "%s: missing lifetime severity in %s, optargt=0p%p, optargp=0p%p, sizeof(\"soft\")=%d\n", + program_name, + optargt, + optargt, + optargp, + (int)sizeof("soft")); + usage(program_name, stderr); + return(1); + } + if(debug) { + fprintf(stdout, + "%s: debug: life_severity=%d, optargt=0p%p=\"%s\", optargp=0p%p=\"%s\", sizeof(\"soft\")=%d\n", + program_name, + life_severity, + optargt, + optargt, + optargp, + optargp, + (int)sizeof("soft")); + } + if(*(optargp++) != '-') { + fprintf(stderr, + "%s: expected '-' after severity of lifetime parameter to --life option.\n", + program_name); + usage(program_name, stderr); + return(1); + } + if(debug) { + fprintf(stdout, + "%s: debug: optargt=0p%p=\"%s\", optargp=0p%p=\"%s\", strlen(optargt)=%d, strlen(optargp)=%d, strncmp(optargp, \"addtime\", sizeof(\"addtime\")-1)=%d\n", + program_name, + optargt, + optargt, + optargp, + optargp, + (int)strlen(optargt), + (int)strlen(optargp), + strncmp(optargp, "addtime", sizeof("addtime")-1)); + } + if(strncmp(optargp, "allocations", sizeof("allocations")-1) == 0) { + life_type = life_alloc; + optargp += sizeof("allocations")-1; + } else if(strncmp(optargp, "bytes", sizeof("bytes")-1) == 0) { + life_type = life_bytes; + optargp += sizeof("bytes")-1; + } else if(strncmp(optargp, "addtime", sizeof("addtime")-1) == 0) { + life_type = life_addtime; + optargp += sizeof("addtime")-1; + } else if(strncmp(optargp, "usetime", sizeof("usetime")-1) == 0) { + life_type = life_usetime; + optargp += sizeof("usetime")-1; + } else if(strncmp(optargp, "packets", sizeof("packets")-1) == 0) { + life_type = life_packets; + optargp += sizeof("packets")-1; + } else { + fprintf(stderr, + "%s: missing lifetime type after '-' in %s\n", + program_name, + optargt); + usage(program_name, stderr); + return(1); + } + if(debug) { + fprintf(stdout, + "%s: debug: life_type=%d\n", + program_name, + life_type); + } + if(life_opt[life_severity][life_type] != NULL) { + fprintf(stderr, + "%s: Error, lifetime parameter redefined:%s, already defined as:0p%p\n", + program_name, + optargt, + life_opt[life_severity][life_type]); + return(1); + } + if(*(optargp++) != '=') { + fprintf(stderr, + "%s: expected '=' after type of lifetime parameter to --life option.\n", + program_name); + usage(program_name, stderr); + return(1); + } + if(debug) { + fprintf(stdout, + "%s: debug: optargt=0p%p, optargt+strlen(optargt)=0p%p, optargp=0p%p, strlen(optargp)=%d\n", + program_name, + optargt, + optargt+strlen(optargt), + optargp, + (int)strlen(optargp)); + } + if(strlen(optargp) == 0) { + fprintf(stderr, + "%s: expected value after '=' in --life option. optargt=0p%p, optargt+strlen(optargt)=0p%p, optargp=0p%p\n", + program_name, + optargt, + optargt+strlen(optargt), + optargp); + usage(program_name, stderr); + return(1); + } + life[life_severity][life_type] = strtoul(optargp, &endptr, 0); + + if(!((endptr == optargp + strlen(optargp)) || (endptr == optargp + strcspn(optargp, ", ")))) { + fprintf(stderr, + "%s: Invalid character='%c' at offset %d in lifetime option parameter: '%s', parameter string is %d characters long, %d valid value characters found.\n", + program_name, + *endptr, + (int)(endptr - optarg), + optarg, + (int)strlen(optarg), + (int)(strcspn(optargp, ", ") - 1)); + return(1); + } + life_opt[life_severity][life_type] = optargt; + if(debug) { + fprintf(stdout, "%s lifetime %s set to %d.\n", + program_name, optargt, life[life_severity][life_type]); + } + optargp=endptr+1; + } while(*endptr==',' || isspace(*endptr)); + + return(0); +} + +int +pfkey_register(uint8_t satype) { + /* for registering SA types that can be negotiated */ + int error; + ssize_t wlen; + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + struct sadb_msg *pfkey_msg; + + pfkey_extensions_init(extensions); + error = pfkey_msg_hdr_build(&extensions[0], + SADB_REGISTER, + satype, + 0, + ++pfkey_seq, + getpid()); + if(error != 0) { + fprintf(stderr, "%s: Trouble building message header, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + return(1); + } + + error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); + if(error != 0) { + fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + return(1); + } + wlen = write(pfkey_sock, pfkey_msg, + pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); + if(wlen != (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) { + /* cleanup code here */ + if(wlen < 0) + fprintf(stderr, "%s: Trouble writing to channel PF_KEY: %s\n", + program_name, + strerror(errno)); + else + fprintf(stderr, "%s: write to channel PF_KEY truncated.\n", + program_name); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + return(1); + } + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + + return(0); +} + +static struct option const longopts[] = +{ + {"ah", 1, 0, 'H'}, + {"esp", 1, 0, 'P'}, + {"comp", 1, 0, 'Z'}, + {"ip4", 0, 0, '4'}, + {"ip6", 0, 0, '6'}, + {"del", 0, 0, 'd'}, + + {"authkey", 1, 0, 'A'}, + {"enckey", 1, 0, 'E'}, + {"edst", 1, 0, 'e'}, + {"spi", 1, 0, 's'}, + {"proto", 1, 0, 'p'}, + {"af", 1, 0, 'a'}, + {"replay_window", 1, 0, 'w'}, + {"iv", 1, 0, 'i'}, + {"dst", 1, 0, 'D'}, + {"src", 1, 0, 'S'}, + {"said", 1, 0, 'I'}, + + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'v'}, + {"clear", 0, 0, 'c'}, + {"label", 1, 0, 'l'}, + {"debug", 0, 0, 'g'}, + {"optionsfrom", 1, 0, '+'}, + {"life", 1, 0, 'f'}, + {"saref", 0, 0, 'r'}, + {"listenreply", 0, 0, 'R'}, + {0, 0, 0, 0} +}; + +int +main(int argc, char *argv[]) +{ + char *endptr; + __u32 spi = 0; + int c, previous = -1; +/* int ret; */ + ip_said said; + size_t sa_len; + const char* error_s; + char ipaddr_txt[ADDRTOT_BUF]; + char ipsaid_txt[SATOT_BUF]; + + int error = 0; + ssize_t io_error; + int argcount = argc; + pid_t mypid; + int listenreply = 0; + + unsigned char authalg, encryptalg; + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + struct sadb_msg *pfkey_msg; + char *iv_opt, *akey_opt, *ekey_opt, *alg_opt, *edst_opt, *spi_opt, *proto_opt, *af_opt, *said_opt, *dst_opt, *src_opt; +#if 0 + ip_address pfkey_address_p_ska; + ip_address pfkey_ident_s_ska; + ip_address pfkey_ident_d_ska; +#endif + uint32_t life[life_maxsever][life_maxtype]; + char *life_opt[life_maxsever][life_maxtype]; + + program_name = argv[0]; + mypid = getpid(); + + memset(&said, 0, sizeof(said)); + iv_opt = akey_opt = ekey_opt = alg_opt = edst_opt = spi_opt = proto_opt = af_opt = said_opt = dst_opt = src_opt = NULL; + { + int i,j; + for(i = 0; i < life_maxsever; i++) { + for(j = 0; j < life_maxtype; j++) { + life_opt[i][j] = NULL; + life[i][j] = 0; + } + } + } + + while((c = getopt_long(argc, argv, ""/*"H:P:Z:46dcA:E:e:s:a:w:i:D:S:hvgl:+:f:"*/, longopts, 0)) != EOF) { + switch(c) { + case 'g': + debug = 1; + pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX; + argcount--; + break; + + case 'R': + listenreply = 1; + argcount--; + break; + + case 'r': + saref = 1; + argcount--; + break; + + case 'l': + program_name = malloc(strlen(argv[0]) + + 10 /* update this when changing the sprintf() */ + + strlen(optarg)); + sprintf(program_name, "%s --label %s", + argv[0], + optarg); + argcount -= 2; + break; + case 'H': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + if (!strcmp(optarg, "hmac-md5-96")) { + alg = XF_AHHMACMD5; + } else if(!strcmp(optarg, "hmac-sha1-96")) { + alg = XF_AHHMACSHA1; + } else { + fprintf(stderr, "%s: Unknown authentication algorithm '%s' follows '--ah' option.\n", + program_name, optarg); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case 'P': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + if (!strcmp(optarg, "3des-md5-96")) { + alg = XF_ESP3DESMD596; + } else if(!strcmp(optarg, "3des-sha1-96")) { + alg = XF_ESP3DESSHA196; + } else if(!strcmp(optarg, "3des")) { + alg = XF_ESP3DES; +#ifndef NO_KERNEL_ALG + } else if((alg_info=alg_info_esp_create_from_str(optarg, &alg_err))) { + int esp_ealg_id, esp_aalg_id; + alg = XF_OTHER_ALG; + if (alg_info->alg_info_cnt>1) { + fprintf(stderr, "%s: Invalid encryption algorithm '%s' " + "follows '--esp' option: lead too many(%d) " + "transforms\n", + program_name, optarg, alg_info->alg_info_cnt); + exit(1); + } + alg_string=optarg; + esp_info=&alg_info->esp[0]; + if (debug) { + fprintf(stdout, "%s: alg_info: cnt=%d ealg[0]=%d aalg[0]=%d\n", + program_name, + alg_info->alg_info_cnt, + esp_info->encryptalg, + esp_info->authalg); + } + esp_ealg_id=esp_info->esp_ealg_id; + esp_aalg_id=esp_info->esp_aalg_id; + if (kernel_alg_proc_read()==0) { + proc_read_ok++; + if (!kernel_alg_esp_enc_ok(esp_ealg_id, 0, 0)) + { + fprintf(stderr, "%s: ESP encryptalg=%d (\"%s\") " + "not present\n", + program_name, + esp_ealg_id, + enum_name(&esp_transformid_names, esp_ealg_id)); + exit(1); + } + if (!kernel_alg_esp_auth_ok(esp_aalg_id, 0)) + { + fprintf(stderr, "%s: ESP authalg=%d (\"%s\")" + "not present\n", + program_name, + esp_aalg_id, + enum_name(&auth_alg_names, esp_aalg_id)); + exit(1); + } + } +#endif /* NO_KERNEL_ALG */ + } else { + fprintf(stderr, "%s: Invalid encryption algorithm '%s' follows '--esp' option.\n", + program_name, optarg); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case 'Z': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + if (!strcmp(optarg, "deflate")) { + alg = XF_COMPDEFLATE; + } else { + fprintf(stderr, "%s: Unknown compression algorithm '%s' follows '--comp' option.\n", + program_name, optarg); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case '4': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + alg = XF_IP4; + address_family = AF_INET; + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case '6': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + alg = XF_IP6; + address_family = AF_INET6; + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case 'd': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + alg = XF_DEL; + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case 'c': + if(alg) { + fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", + program_name); + exit(1); + } + alg = XF_CLR; + if(debug) { + fprintf(stdout, "%s: Algorithm %d selected.\n", + program_name, + alg); + } + alg_opt = optarg; + break; + case 'e': + if(said_opt) { + fprintf(stderr, "%s: Error, EDST parameter redefined:%s, already defined in SA:%s\n", + program_name, optarg, said_opt); + exit (1); + } + if(edst_opt) { + fprintf(stderr, "%s: Error, EDST parameter redefined:%s, already defined as:%s\n", + program_name, optarg, edst_opt); + exit (1); + } + error_s = ttoaddr(optarg, 0, address_family, &edst); + if(error_s != NULL) { + if(error_s) { + fprintf(stderr, "%s: Error, %s converting --edst argument:%s\n", + program_name, error_s, optarg); + exit (1); + } + } + edst_opt = optarg; + if(debug) { + addrtot(&edst, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: edst=%s.\n", + program_name, + ipaddr_txt); + } + break; + case 's': + if(said_opt) { + fprintf(stderr, "%s: Error, SPI parameter redefined:%s, already defined in SA:%s\n", + program_name, optarg, said_opt); + exit (1); + } + if(spi_opt) { + fprintf(stderr, "%s: Error, SPI parameter redefined:%s, already defined as:%s\n", + program_name, optarg, spi_opt); + exit (1); + } + spi = strtoul(optarg, &endptr, 0); + if(!(endptr == optarg + strlen(optarg))) { + fprintf(stderr, "%s: Invalid character in SPI parameter: %s\n", + program_name, optarg); + exit (1); + } + if(spi < 0x100) { + fprintf(stderr, "%s: Illegal reserved spi: %s => 0x%x Must be larger than 0x100.\n", + program_name, optarg, spi); + exit(1); + } + spi_opt = optarg; + break; + case 'p': + if(said_opt) { + fprintf(stderr, "%s: Error, PROTO parameter redefined:%s, already defined in SA:%s\n", + program_name, optarg, said_opt); + exit (1); + } + if(proto_opt) { + fprintf(stderr, "%s: Error, PROTO parameter redefined:%s, already defined as:%s\n", + program_name, optarg, proto_opt); + exit (1); + } + if(!strcmp(optarg, "ah")) + proto = SA_AH; + if(!strcmp(optarg, "esp")) + proto = SA_ESP; + if(!strcmp(optarg, "tun")) + proto = SA_IPIP; + if(!strcmp(optarg, "comp")) + proto = SA_COMP; + if(proto == 0) { + fprintf(stderr, "%s: Invalid PROTO parameter: %s\n", + program_name, optarg); + exit (1); + } + proto_opt = optarg; + break; + case 'a': + if(said_opt) { + fprintf(stderr, "%s: Error, ADDRESS FAMILY parameter redefined:%s, already defined in SA:%s\n", + program_name, optarg, said_opt); + exit (1); + } + if(af_opt) { + fprintf(stderr, "%s: Error, ADDRESS FAMILY parameter redefined:%s, already defined as:%s\n", + program_name, optarg, af_opt); + exit (1); + } + if(strcmp(optarg, "inet") == 0) { + address_family = AF_INET; + /* currently we ensure that all addresses belong to the same address family */ + anyaddr(address_family, &dst); + anyaddr(address_family, &edst); + anyaddr(address_family, &src); + } + if(strcmp(optarg, "inet6") == 0) { + address_family = AF_INET6; + /* currently we ensure that all addresses belong to the same address family */ + anyaddr(address_family, &dst); + anyaddr(address_family, &edst); + anyaddr(address_family, &src); + } + if((strcmp(optarg, "inet") != 0) && (strcmp(optarg, "inet6") != 0)) { + fprintf(stderr, "%s: Invalid ADDRESS FAMILY parameter: %s.\n", + program_name, optarg); + exit (1); + } + af_opt = optarg; + break; + case 'I': + if(said_opt) { + fprintf(stderr, "%s: Error, SAID parameter redefined:%s, already defined in SA:%s\n", + program_name, optarg, said_opt); + exit (1); + } + if(proto_opt) { + fprintf(stderr, "%s: Error, PROTO parameter redefined in SA:%s, already defined as:%s\n", + program_name, optarg, proto_opt); + exit (1); + } + if(edst_opt) { + fprintf(stderr, "%s: Error, EDST parameter redefined in SA:%s, already defined as:%s\n", + program_name, optarg, edst_opt); + exit (1); + } + if(spi_opt) { + fprintf(stderr, "%s: Error, SPI parameter redefined in SA:%s, already defined as:%s\n", + program_name, optarg, spi_opt); + exit (1); + } + error_s = ttosa(optarg, 0, &said); + if(error_s != NULL) { + fprintf(stderr, "%s: Error, %s converting --sa argument:%s\n", + program_name, error_s, optarg); + exit (1); + } + if(debug) { + satot(&said, 0, ipsaid_txt, sizeof(ipsaid_txt)); + fprintf(stdout, "%s: said=%s.\n", + program_name, + ipsaid_txt); + } + /* init the src and dst with the same address family */ + if(address_family == 0) { + address_family = addrtypeof(&said.dst); + } else if(address_family != addrtypeof(&said.dst)) { + fprintf(stderr, "%s: Error, specified address family (%d) is different that of SAID: %s\n", + program_name, address_family, optarg); + exit (1); + } + anyaddr(address_family, &dst); + anyaddr(address_family, &edst); + anyaddr(address_family, &src); + said_opt = optarg; + break; + case 'A': + if(optarg[0] == '0') { + switch(optarg[1]) { + case 't': + case 'x': + case 's': + break; + default: + fprintf(stderr, "%s: Authentication key must have a '0x', '0t' or '0s' prefix to select the format: %s\n", + program_name, optarg); + exit(1); + } + } + authkeylen = atodata(optarg, 0, NULL, 0); + if(!authkeylen) { + fprintf(stderr, "%s: unknown format or syntax error in authentication key: %s\n", + program_name, optarg); + exit (1); + } + authkey = malloc(authkeylen); + if(authkey == NULL) { + fprintf(stderr, "%s: Memory allocation error.\n", program_name); + exit(1); + } + memset(authkey, 0, authkeylen); + authkeylen = atodata(optarg, 0, authkey, authkeylen); + akey_opt = optarg; + break; + case 'E': + if(optarg[0] == '0') { + switch(optarg[1]) { + case 't': + case 'x': + case 's': + break; + default: + fprintf(stderr, "%s: Encryption key must have a '0x', '0t' or '0s' prefix to select the format: %s\n", + program_name, optarg); + exit(1); + } + } + enckeylen = atodata(optarg, 0, NULL, 0); + if(!enckeylen) { + fprintf(stderr, "%s: unknown format or syntax error in encryption key: %s\n", + program_name, optarg); + exit (1); + } + enckey = malloc(enckeylen); + if(enckey == NULL) { + fprintf(stderr, "%s: Memory allocation error.\n", program_name); + exit(1); + } + memset(enckey, 0, enckeylen); + enckeylen = atodata(optarg, 0, enckey, enckeylen); + ekey_opt = optarg; + break; + case 'w': + replay_window = strtoul(optarg, &endptr, 0); + if(!(endptr == optarg + strlen(optarg))) { + fprintf(stderr, "%s: Invalid character in replay_window parameter: %s\n", + program_name, optarg); + exit (1); + } + if((replay_window < 0x1) || (replay_window > 64)) { + fprintf(stderr, "%s: Failed -- Illegal window size: arg=%s, replay_window=%d, must be 1 <= size <= 64.\n", + program_name, optarg, replay_window); + exit(1); + } + break; + case 'i': + if(optarg[0] == '0') { + switch(optarg[1]) { + case 't': + case 'x': + case 's': + break; + default: + fprintf(stderr, "%s: IV must have a '0x', '0t' or '0s' prefix to select the format, found '%c'.\n", + program_name, optarg[1]); + exit(1); + } + } + ivlen = atodata(optarg, 0, NULL, 0); + if(!ivlen) { + fprintf(stderr, "%s: unknown format or syntax error in IV: %s\n", + program_name, optarg); + exit (1); + } + iv = malloc(ivlen); + if(iv == NULL) { + fprintf(stderr, "%s: Memory allocation error.\n", program_name); + exit(1); + } + memset(iv, 0, ivlen); + ivlen = atodata(optarg, 0, iv, ivlen); + iv_opt = optarg; + break; + case 'D': + if(dst_opt) { + fprintf(stderr, "%s: Error, DST parameter redefined:%s, already defined as:%s\n", + program_name, optarg, dst_opt); + exit (1); + } + error_s = ttoaddr(optarg, 0, address_family, &dst); + if(error_s != NULL) { + fprintf(stderr, "%s: Error, %s converting --dst argument:%s\n", + program_name, error_s, optarg); + exit (1); + } + dst_opt = optarg; + if(debug) { + addrtot(&dst, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: dst=%s.\n", + program_name, + ipaddr_txt); + } + break; + case 'S': + if(src_opt) { + fprintf(stderr, "%s: Error, SRC parameter redefined:%s, already defined as:%s\n", + program_name, optarg, src_opt); + exit (1); + } + error_s = ttoaddr(optarg, 0, address_family, &src); + if(error_s != NULL) { + fprintf(stderr, "%s: Error, %s converting --src argument:%s\n", + program_name, error_s, optarg); + exit (1); + } + src_opt = optarg; + if(debug) { + addrtot(&src, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: src=%s.\n", + program_name, + ipaddr_txt); + } + break; + case 'h': + usage(program_name, stdout); + exit(0); + case '?': + usage(program_name, stderr); + exit(1); + case 'v': + fprintf(stdout, "%s, %s\n", program_name, spi_c_version); + exit(1); + case '+': /* optionsfrom */ + optionsfrom(optarg, &argc, &argv, optind, stderr); + /* no return on error */ + break; + case 'f': + if(parse_life_options(life, + life_opt, + optarg) != 0) { + exit(1); + }; + break; + default: + fprintf(stderr, "%s: unrecognized option '%c', update option processing.\n", + program_name, c); + exit(1); + } + previous = c; + } + if(debug) { + fprintf(stdout, "%s: All options processed.\n", + program_name); + } + + if(argcount == 1) { + system("cat /proc/net/ipsec_spi"); + exit(0); + } + + switch(alg) { +#ifndef NO_KERNEL_ALG + case XF_OTHER_ALG: + /* validate keysizes */ + if (proc_read_ok) { + const struct sadb_alg *alg_p; + size_t keylen, minbits, maxbits; + + alg_p=kernel_alg_sadb_alg_get(SADB_SATYPE_ESP,SADB_EXT_SUPPORTED_ENCRYPT, + esp_info->encryptalg); + assert(alg_p); + keylen=enckeylen * 8; + + if (alg_p->sadb_alg_id==ESP_3DES || alg_p->sadb_alg_id==ESP_DES) { + maxbits=minbits=alg_p->sadb_alg_minbits * 8 /7; + } else { + minbits=alg_p->sadb_alg_minbits; + maxbits=alg_p->sadb_alg_maxbits; + } + /* + * if explicit keylen told in encrypt algo, eg "aes128" + * check actual keylen "equality" + */ + if (esp_info->esp_ealg_keylen && + esp_info->esp_ealg_keylen!=keylen) { + fprintf(stderr, "%s: invalid encryption keylen=%d, " + "required %d by encrypt algo string=\"%s\"\n", + program_name, + (int)keylen, + (int)esp_info->esp_ealg_keylen, + alg_string); + exit(1); + + } + /* thanks DES for this sh*t */ + + if (minbits > keylen || maxbits < keylen) { + fprintf(stderr, "%s: invalid encryption keylen=%d, " + "must be between %d and %d bits\n", + program_name, + (int)keylen, (int)minbits, (int)maxbits); + exit(1); + } + alg_p=kernel_alg_sadb_alg_get(SADB_SATYPE_ESP,SADB_EXT_SUPPORTED_AUTH, + esp_info->authalg); + assert(alg_p); + keylen=authkeylen * 8; + minbits=alg_p->sadb_alg_minbits; + maxbits=alg_p->sadb_alg_maxbits; + if (minbits > keylen || maxbits < keylen) { + fprintf(stderr, "%s: invalid auth keylen=%d, " + "must be between %d and %d bits\n", + program_name, + (int)keylen, (int)minbits, (int)maxbits); + exit(1); + } + + } +#endif /* NO_KERNEL_ALG */ + case XF_IP4: + case XF_IP6: + case XF_DEL: + case XF_AHHMACMD5: + case XF_AHHMACSHA1: + case XF_ESP3DESMD596: + case XF_ESP3DESSHA196: + case XF_ESP3DES: + case XF_COMPDEFLATE: + if(!said_opt) { + if(isanyaddr(&edst)) { + fprintf(stderr, "%s: SA destination not specified.\n", + program_name); + exit(1); + } + if(!spi) { + fprintf(stderr, "%s: SA SPI not specified.\n", + program_name); + exit(1); + } + if(!proto) { + fprintf(stderr, "%s: SA PROTO not specified.\n", + program_name); + exit(1); + } + initsaid(&edst, htonl(spi), proto, &said); + } else { + proto = said.proto; + spi = ntohl(said.spi); + edst = said.dst; + } + if((address_family != 0) && (address_family != addrtypeof(&said.dst))) { + fprintf(stderr, "%s: Defined address family and address family of SA missmatch.\n", + program_name); + exit(1); + } + sa_len = satot(&said, 0, sa, sizeof(sa)); + + if(debug) { + fprintf(stdout, "%s: SA valid.\n", + program_name); + } + break; + case XF_CLR: + break; + default: + fprintf(stderr, "%s: No action chosen. See '%s --help' for usage.\n", + program_name, program_name); + exit(1); + } + + switch(alg) { + case XF_CLR: + case XF_DEL: + case XF_IP4: + case XF_IP6: + case XF_AHHMACMD5: + case XF_AHHMACSHA1: + case XF_ESP3DESMD596: + case XF_ESP3DESSHA196: + case XF_ESP3DES: + case XF_COMPDEFLATE: +#ifndef NO_KERNEL_ALG + case XF_OTHER_ALG: +#endif /* NO_KERNEL_ALG */ + break; + default: + fprintf(stderr, "%s: No action chosen. See '%s --help' for usage.\n", + program_name, program_name); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: Algorithm ok.\n", + program_name); + } + + if((pfkey_sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2) ) < 0) { + fprintf(stderr, "%s: Trouble opening PF_KEY family socket with error: ", + program_name); + switch(errno) { + case ENOENT: + fprintf(stderr, "device does not exist. See FreeS/WAN installation procedure.\n"); + break; + case EACCES: + fprintf(stderr, "access denied. "); + if(getuid() == 0) { + fprintf(stderr, "Check permissions. Should be 600.\n"); + } else { + fprintf(stderr, "You must be root to open this file.\n"); + } + break; + case EUNATCH: + fprintf(stderr, "Netlink not enabled OR KLIPS not loaded.\n"); + break; + case ENODEV: + fprintf(stderr, "KLIPS not loaded or enabled.\n"); + break; + case EBUSY: + fprintf(stderr, "KLIPS is busy. Most likely a serious internal error occured in a previous command. Please report as much detail as possible to development team.\n"); + break; + case EINVAL: + fprintf(stderr, "Invalid argument, KLIPS not loaded or check kernel log messages for specifics.\n"); + break; + case ENOBUFS: + fprintf(stderr, "No kernel memory to allocate SA.\n"); + break; + case ESOCKTNOSUPPORT: + fprintf(stderr, "Algorithm support not available in the kernel. Please compile in support.\n"); + break; + case EEXIST: + fprintf(stderr, "SA already in use. Delete old one first.\n"); + break; + case ENXIO: + fprintf(stderr, "SA does not exist. Cannot delete.\n"); + break; + case EAFNOSUPPORT: + fprintf(stderr, "KLIPS not loaded or enabled.\n"); + break; + default: + fprintf(stderr, "Unknown file open error %d. Please report as much detail as possible to development team.\n", errno); + } + exit(1); + } + +#ifdef MANUAL_IS_NOT_ABLE_TO_NEGOTIATE + /* for registering SA types that can be negotiated */ + if(pfkey_register(SADB_SATYPE_AH) != 0) { + exit(1); + } + if(pfkey_register(SADB_SATYPE_ESP) != 0) { + exit(1); + } + if(pfkey_register(SADB_X_SATYPE_IPIP) != 0) { + exit(1); + } + if(pfkey_register(SADB_X_SATYPE_COMP) != 0) { + exit(1); + } +#endif /* MANUAL_IS_NOT_ABLE_TO_NEGOTIATE */ + + /* Build an SADB_ADD message to send down. */ + /* It needs <base, SA, address(SD), key(AE)> minimum. */ + /* Lifetime(HS) could be added before addresses. */ + pfkey_extensions_init(extensions); + if(debug) { + fprintf(stdout, "%s: extensions=0p%p &extensions=0p%p extensions[0]=0p%p &extensions[0]=0p%p cleared.\n", + program_name, + extensions, + &extensions, + extensions[0], + &extensions[0]); + } + if((error = pfkey_msg_hdr_build(&extensions[0], + (alg == XF_DEL ? SADB_DELETE : alg == XF_CLR ? SADB_FLUSH : SADB_ADD), + proto2satype(proto), + 0, + ++pfkey_seq, + mypid))) { + fprintf(stderr, "%s: Trouble building message header, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: extensions=0p%p &extensions=0p%p extensions[0]=0p%p &extensions[0]=0p%p set w/msghdr.\n", + program_name, + extensions, + &extensions, + extensions[0], + &extensions[0]); + } + if(debug) { + fprintf(stdout, "%s: base message assembled.\n", program_name); + } + + switch(alg) { + case XF_AHHMACMD5: + case XF_ESP3DESMD596: + authalg = SADB_AALG_MD5_HMAC; + break; + case XF_AHHMACSHA1: + case XF_ESP3DESSHA196: + authalg = SADB_AALG_SHA1_HMAC; + break; +#ifndef NO_KERNEL_ALG + case XF_OTHER_ALG: + authalg= esp_info->authalg; + if(debug) { + fprintf(stdout, "%s: debug: authalg=%d\n", + program_name, authalg); + } + break; +#endif /* NO_KERNEL_ALG */ + case XF_ESP3DESMD5: + default: + authalg = SADB_AALG_NONE; + } + switch(alg) { + case XF_ESP3DES: + case XF_ESP3DESMD596: + case XF_ESP3DESSHA196: + encryptalg = SADB_EALG_3DES_CBC; + break; + case XF_COMPDEFLATE: + encryptalg = SADB_X_CALG_DEFLATE; + break; +#ifndef NO_KERNEL_ALG + case XF_OTHER_ALG: + encryptalg= esp_info->encryptalg; + if(debug) { + fprintf(stdout, "%s: debug: encryptalg=%d\n", + program_name, encryptalg); + } + break; +#endif /* NO_KERNEL_ALG */ + default: + encryptalg = SADB_EALG_NONE; + } + if(!(alg == XF_CLR /* IE: pfkey_msg->sadb_msg_type == SADB_FLUSH */)) { + if((error = pfkey_sa_build(&extensions[SADB_EXT_SA], + SADB_EXT_SA, + htonl(spi), /* in network order */ + replay_window, + SADB_SASTATE_MATURE, + authalg, + encryptalg, + 0))) { + fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: extensions[0]=0p%p previously set with msg_hdr.\n", + program_name, + extensions[0]); + } + if(debug) { + fprintf(stdout, "%s: assembled SA extension, pfkey msg authalg=%d encalg=%d.\n", + program_name, + authalg, + encryptalg); + } + + if(debug) { + int i,j; + for(i = 0; i < life_maxsever; i++) { + for(j = 0; j < life_maxtype; j++) { + fprintf(stdout, "%s: i=%d, j=%d, life_opt[%d][%d]=0p%p, life[%d][%d]=%d\n", + program_name, + i, j, i, j, life_opt[i][j], i, j, life[i][j]); + } + } + } + if(life_opt[life_soft][life_alloc] != NULL || + life_opt[life_soft][life_bytes] != NULL || + life_opt[life_soft][life_addtime] != NULL || + life_opt[life_soft][life_usetime] != NULL || + life_opt[life_soft][life_packets] != NULL) { + if((error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_SOFT], + SADB_EXT_LIFETIME_SOFT, + life[life_soft][life_alloc],/*-1,*/ /*allocations*/ + life[life_soft][life_bytes],/*-1,*/ /*bytes*/ + life[life_soft][life_addtime],/*-1,*/ /*addtime*/ + life[life_soft][life_usetime],/*-1,*/ /*usetime*/ + life[life_soft][life_packets]/*-1*/))) { /*packets*/ + fprintf(stderr, "%s: Trouble building lifetime_s extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: lifetime_s extension assembled.\n", + program_name); + } + } + + if(life_opt[life_hard][life_alloc] != NULL || + life_opt[life_hard][life_bytes] != NULL || + life_opt[life_hard][life_addtime] != NULL || + life_opt[life_hard][life_usetime] != NULL || + life_opt[life_hard][life_packets] != NULL) { + if((error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_HARD], + SADB_EXT_LIFETIME_HARD, + life[life_hard][life_alloc],/*-1,*/ /*allocations*/ + life[life_hard][life_bytes],/*-1,*/ /*bytes*/ + life[life_hard][life_addtime],/*-1,*/ /*addtime*/ + life[life_hard][life_usetime],/*-1,*/ /*usetime*/ + life[life_hard][life_packets]/*-1*/))) { /*packets*/ + fprintf(stderr, "%s: Trouble building lifetime_h extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: lifetime_h extension assembled.\n", + program_name); + } + } + + if(debug) { + addrtot(&src, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: assembling address_s extension (%s).\n", + program_name, ipaddr_txt); + } + + if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, + 0, + sockaddrof(&src)))) { + addrtot(&src, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stderr, "%s: Trouble building address_s extension (%s), error=%d.\n", + program_name, ipaddr_txt, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + ip_address temp_addr; + + switch(address_family) { + case AF_INET: + initaddr((const unsigned char *)&(((struct sockaddr_in*)( ((struct sadb_address*)(extensions[SADB_EXT_ADDRESS_SRC])) + 1))->sin_addr), + sockaddrlenof(&src), address_family, &temp_addr); + break; + case AF_INET6: + initaddr((const unsigned char *)&(((struct sockaddr_in6*)( ((struct sadb_address*)(extensions[SADB_EXT_ADDRESS_SRC])) + 1))->sin6_addr), + sockaddrlenof(&src), address_family, &temp_addr); + break; + default: + fprintf(stdout, "%s: unknown address family (%d).\n", + program_name, address_family); + exit(1); + } + addrtot(&temp_addr, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: address_s extension assembled (%s).\n", + program_name, ipaddr_txt); + } + + if(debug) { + addrtot(&edst, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: assembling address_d extension (%s).\n", + program_name, ipaddr_txt); + } + + if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, + 0, + sockaddrof(&edst)))) { + addrtot(&edst, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stderr, "%s: Trouble building address_d extension (%s), error=%d.\n", + program_name, ipaddr_txt, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + ip_address temp_addr; + switch(address_family) { + case AF_INET: + initaddr((const unsigned char *)&(((struct sockaddr_in*)( ((struct sadb_address*)(extensions[SADB_EXT_ADDRESS_DST])) + 1))->sin_addr), + 4, address_family, &temp_addr); + break; + case AF_INET6: + initaddr((const unsigned char *)&(((struct sockaddr_in6*)( ((struct sadb_address*)(extensions[SADB_EXT_ADDRESS_DST])) + 1))->sin6_addr), + 16, address_family, &temp_addr); + break; + default: + fprintf(stdout, "%s: unknown address family (%d).\n", + program_name, address_family); + exit(1); + } + addrtot(&temp_addr, 0, ipaddr_txt, sizeof(ipaddr_txt)); + fprintf(stdout, "%s: address_d extension assembled (%s).\n", + program_name, ipaddr_txt); + } + +#if PFKEY_PROXY + anyaddr(address_family, &pfkey_address_p_ska); + if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_PROXY], + SADB_EXT_ADDRESS_PROXY, + 0, + 0, + sockaddrof(&pfkey_address_p_ska)))) { + fprintf(stderr, "%s: Trouble building address_p extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: address_p extension assembled.\n", program_name); + } +#endif /* PFKEY_PROXY */ + + switch(alg) { +#ifndef NO_KERNEL_ALG + /* Allow no auth ... after all is local root decision 8) */ + case XF_OTHER_ALG: + if (!authalg) + break; +#endif /* NO_KERNEL_ALG */ + case XF_AHHMACMD5: + case XF_ESP3DESMD596: + case XF_AHHMACSHA1: + case XF_ESP3DESSHA196: + if((error = pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH], + SADB_EXT_KEY_AUTH, + authkeylen * 8, + authkey))) { + fprintf(stderr, "%s: Trouble building key_a extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: key_a extension assembled.\n", + program_name); + } + break; + default: + break; + } + + switch(alg) { + case XF_ESP3DES: + case XF_ESP3DESMD596: + case XF_ESP3DESSHA196: +#ifndef NO_KERNEL_ALG + case XF_OTHER_ALG: +#endif /* NO_KERNEL_ALG */ + if((error = pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT], + SADB_EXT_KEY_ENCRYPT, + enckeylen * 8, + enckey))) { + fprintf(stderr, "%s: Trouble building key_e extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: key_e extension assembled.\n", + program_name); + } + break; + default: + break; + } + +#ifdef PFKEY_IDENT /* GG: looks wierd, not touched */ + if((pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_SRC], + SADB_EXT_IDENTITY_SRC, + SADB_IDENTTYPE_PREFIX, + 0, + strlen(pfkey_ident_s_ska), + pfkey_ident_s_ska))) { + fprintf(stderr, "%s: Trouble building ident_s extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(subnettoa(addr, mask, format, pfkey_ident_s_ska, + sizeof(pfkey_ident_s_ska) ) != + sizeof(pfkey_ident_s_ska) ) { + exit (1); + } + + if((error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_DST], + SADB_EXT_IDENTITY_DST, + SADB_IDENTTYPE_PREFIX, + 0, + strlen(pfkey_ident_d_ska), + pfkey_ident_d_ska))) { + fprintf(stderr, "%s: Trouble building ident_d extension, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + exit(1); + } + if(subnettoa(addr, mask, format, pfkey_ident_d_ska, + sizeof(pfkey_ident_d_ska) ) != + sizeof(pfkey_ident_d_ska) ) { + exit (1); + } + + if(debug) { + fprintf(stdout, "%s: ident extensions assembled.\n", + program_name); + } +#endif /* PFKEY_IDENT */ + } + + if(debug) { + fprintf(stdout, "%s: assembling pfkey msg....\n", + program_name); + } + if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) { + fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n", + program_name, error); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + exit(1); + } + if(debug) { + fprintf(stdout, "%s: assembled.\n", + program_name); + } + if(debug) { + fprintf(stdout, "%s: writing pfkey msg.\n", + program_name); + } + io_error = write(pfkey_sock, + pfkey_msg, + pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); + if(io_error < 0) { + fprintf(stderr, "%s: pfkey write failed (errno=%d): ", + program_name, errno); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + switch(errno) { + case EACCES: + fprintf(stderr, "access denied. "); + if(getuid() == 0) { + fprintf(stderr, "Check permissions. Should be 600.\n"); + } else { + fprintf(stderr, "You must be root to open this file.\n"); + } + break; + case EUNATCH: + fprintf(stderr, "Netlink not enabled OR KLIPS not loaded.\n"); + break; + case EBUSY: + fprintf(stderr, "KLIPS is busy. Most likely a serious internal error occured in a previous command. Please report as much detail as possible to development team.\n"); + break; + case EINVAL: + fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n"); + break; + case ENODEV: + fprintf(stderr, "KLIPS not loaded or enabled.\n"); + fprintf(stderr, "No device?!?\n"); + break; + case ENOBUFS: + fprintf(stderr, "No kernel memory to allocate SA.\n"); + break; + case ESOCKTNOSUPPORT: + fprintf(stderr, "Algorithm support not available in the kernel. Please compile in support.\n"); + break; + case EEXIST: + fprintf(stderr, "SA already in use. Delete old one first.\n"); + break; + case ENOENT: + fprintf(stderr, "device does not exist. See FreeS/WAN installation procedure.\n"); + break; + case ENXIO: + case ESRCH: + fprintf(stderr, "SA does not exist. Cannot delete.\n"); + break; + case ENOSPC: + fprintf(stderr, "no room in kernel SAref table. Cannot process request.\n"); + break; + case ESPIPE: + fprintf(stderr, "kernel SAref table internal error. Cannot process request.\n"); + break; + default: + fprintf(stderr, "Unknown socket write error %d (%s). Please report as much detail as possible to development team.\n", + errno, strerror(errno)); + } + exit(1); + } else if (io_error != (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) { + fprintf(stderr, "%s: pfkey write truncated to %d bytes\n", + program_name, (int)io_error); + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + exit(1); + } + + if(debug) { + fprintf(stdout, "%s: pfkey command written to socket.\n", + program_name); + } + + if(pfkey_msg) { + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + } + if(debug) { + fprintf(stdout, "%s: pfkey message buffer freed.\n", + program_name); + } + if(authkey) { + memset((caddr_t)authkey, 0, authkeylen); + free(authkey); + } + if(enckey) { + memset((caddr_t)enckey, 0, enckeylen); + free(enckey); + } + if(iv) { + memset((caddr_t)iv, 0, ivlen); + free(iv); + } + + if(listenreply || saref) { + ssize_t readlen; + unsigned char pfkey_buf[PFKEYv2_MAX_MSGSIZE]; + + while((readlen = read(pfkey_sock, pfkey_buf, sizeof(pfkey_buf))) > 0) { + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + pfkey_extensions_init(extensions); + pfkey_msg = (struct sadb_msg *)pfkey_buf; + + /* first, see if we got enough for an sadb_msg */ + if((size_t)readlen < sizeof(struct sadb_msg)) { + if(debug) { + printf("%s: runt packet of size: %ld (<%lu)\n", + program_name, (long)readlen, (unsigned long)sizeof(struct sadb_msg)); + } + continue; + } + + /* okay, we got enough for a message, print it out */ + if(debug) { + printf("%s: pfkey v%d msg received. type=%d(%s) seq=%d len=%d pid=%d errno=%d satype=%d(%s)\n", + program_name, + pfkey_msg->sadb_msg_version, + pfkey_msg->sadb_msg_type, + pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type), + pfkey_msg->sadb_msg_seq, + pfkey_msg->sadb_msg_len, + pfkey_msg->sadb_msg_pid, + pfkey_msg->sadb_msg_errno, + pfkey_msg->sadb_msg_satype, + satype2name(pfkey_msg->sadb_msg_satype)); + } + + if(readlen != (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) + { + if(debug) { + printf("%s: packet size read from socket=%d doesn't equal sadb_msg_len %u * %u; message not decoded\n", + program_name, + (int)readlen, + (unsigned)pfkey_msg->sadb_msg_len, + (unsigned)IPSEC_PFKEYv2_ALIGN); + } + continue; + } + + if (pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_OUT)) { + if(debug) { + printf("%s: unparseable PF_KEY message.\n", + program_name); + } + continue; + } else { + if(debug) { + printf("%s: parseable PF_KEY message.\n", + program_name); + } + } + if((pid_t)pfkey_msg->sadb_msg_pid == mypid) { + if(saref) { + printf("%s: saref=%d\n", + program_name, + (extensions[SADB_EXT_SA] != NULL) + ? ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_x_sa_ref + : IPSEC_SAREF_NULL); + } + break; + } + } + } + (void) close(pfkey_sock); /* close the socket */ + if(debug || listenreply) { + printf("%s: exited normally\n", program_name); + } + exit(0); +} |