summaryrefslogtreecommitdiff
path: root/programs/spi
diff options
context:
space:
mode:
Diffstat (limited to 'programs/spi')
-rw-r--r--programs/spi/.cvsignore1
-rw-r--r--programs/spi/Makefile69
-rw-r--r--programs/spi/spi.5213
-rw-r--r--programs/spi/spi.8525
-rw-r--r--programs/spi/spi.c1689
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);
+}